<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en"><head>

<meta charset="utf-8">
<meta name="generator" content="quarto-1.4.555">

<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=yes">

<meta name="author" content="梁昊">

<title>医学生入门机器学习-tidymodels基础与流程</title>
<style>
code{white-space: pre-wrap;}
span.smallcaps{font-variant: small-caps;}
div.columns{display: flex; gap: min(4vw, 1.5em);}
div.column{flex: auto; overflow-x: auto;}
div.hanging-indent{margin-left: 1.5em; text-indent: -1.5em;}
ul.task-list{list-style: none;}
ul.task-list li input[type="checkbox"] {
  width: 0.8em;
  margin: 0 0.8em 0.2em -1em; /* quarto-specific, see https://github.com/quarto-dev/quarto-cli/issues/4556 */ 
  vertical-align: middle;
}
/* CSS for syntax highlighting */
pre > code.sourceCode { white-space: pre; position: relative; }
pre > code.sourceCode > span { line-height: 1.25; }
pre > code.sourceCode > span:empty { height: 1.2em; }
.sourceCode { overflow: visible; }
code.sourceCode > span { color: inherit; text-decoration: inherit; }
div.sourceCode { margin: 1em 0; }
pre.sourceCode { margin: 0; }
@media screen {
div.sourceCode { overflow: auto; }
}
@media print {
pre > code.sourceCode { white-space: pre-wrap; }
pre > code.sourceCode > span { text-indent: -5em; padding-left: 5em; }
}
pre.numberSource code
  { counter-reset: source-line 0; }
pre.numberSource code > span
  { position: relative; left: -4em; counter-increment: source-line; }
pre.numberSource code > span > a:first-child::before
  { content: counter(source-line);
    position: relative; left: -1em; text-align: right; vertical-align: baseline;
    border: none; display: inline-block;
    -webkit-touch-callout: none; -webkit-user-select: none;
    -khtml-user-select: none; -moz-user-select: none;
    -ms-user-select: none; user-select: none;
    padding: 0 4px; width: 4em;
  }
pre.numberSource { margin-left: 3em;  padding-left: 4px; }
div.sourceCode
  {   }
@media screen {
pre > code.sourceCode > span > a:first-child::before { text-decoration: underline; }
}
</style>


<script src="00.Preface_files/libs/clipboard/clipboard.min.js"></script>
<script src="00.Preface_files/libs/quarto-html/quarto.js"></script>
<script src="00.Preface_files/libs/quarto-html/popper.min.js"></script>
<script src="00.Preface_files/libs/quarto-html/tippy.umd.min.js"></script>
<script src="00.Preface_files/libs/quarto-html/anchor.min.js"></script>
<link href="00.Preface_files/libs/quarto-html/tippy.css" rel="stylesheet">
<link href="00.Preface_files/libs/quarto-html/quarto-syntax-highlighting.css" rel="stylesheet" id="quarto-text-highlighting-styles">
<script src="00.Preface_files/libs/bootstrap/bootstrap.min.js"></script>
<link href="00.Preface_files/libs/bootstrap/bootstrap-icons.css" rel="stylesheet">
<link href="00.Preface_files/libs/bootstrap/bootstrap.min.css" rel="stylesheet" id="quarto-bootstrap" data-mode="light">
<script src="00.Preface_files/libs/quarto-contrib/glightbox/glightbox.min.js"></script>
<link href="00.Preface_files/libs/quarto-contrib/glightbox/glightbox.min.css" rel="stylesheet">
<link href="00.Preface_files/libs/quarto-contrib/glightbox/lightbox.css" rel="stylesheet">


</head>

<body>

<div id="quarto-content" class="page-columns page-rows-contents page-layout-article">
<div id="quarto-margin-sidebar" class="sidebar margin-sidebar">
  <nav id="TOC" role="doc-toc" class="toc-active">
    <h2 id="toc-title">Table of contents</h2>
   
  <ul>
  <li><a href="#写给医学伙伴的悄悄话" id="toc-写给医学伙伴的悄悄话" class="nav-link active" data-scroll-target="#写给医学伙伴的悄悄话"><span class="header-section-number">1</span> 写给医学伙伴的悄悄话</a></li>
  <li><a href="#医学数据" id="toc-医学数据" class="nav-link" data-scroll-target="#医学数据"><span class="header-section-number">2</span> 医学数据</a>
  <ul class="collapse">
  <li><a href="#文本数据" id="toc-文本数据" class="nav-link" data-scroll-target="#文本数据"><span class="header-section-number">2.1</span> 文本数据</a></li>
  <li><a href="#其他数据" id="toc-其他数据" class="nav-link" data-scroll-target="#其他数据"><span class="header-section-number">2.2</span> 其他数据</a></li>
  </ul></li>
  <li><a href="#机器学习类型和业务逻辑" id="toc-机器学习类型和业务逻辑" class="nav-link" data-scroll-target="#机器学习类型和业务逻辑"><span class="header-section-number">3</span> 机器学习类型和业务逻辑</a></li>
  <li><a href="#机器学习的流程" id="toc-机器学习的流程" class="nav-link" data-scroll-target="#机器学习的流程"><span class="header-section-number">4</span> 机器学习的流程</a></li>
  <li><a href="#tidymodels实践" id="toc-tidymodels实践" class="nav-link" data-scroll-target="#tidymodels实践"><span class="header-section-number">5</span> tidymodels实践</a>
  <ul class="collapse">
  <li><a href="#载入package" id="toc-载入package" class="nav-link" data-scroll-target="#载入package"><span class="header-section-number">5.1</span> 载入package</a></li>
  <li><a href="#tidymodels流程初体验" id="toc-tidymodels流程初体验" class="nav-link" data-scroll-target="#tidymodels流程初体验"><span class="header-section-number">5.2</span> tidymodels流程初体验</a></li>
  <li><a href="#交叉验证优化训练" id="toc-交叉验证优化训练" class="nav-link" data-scroll-target="#交叉验证优化训练"><span class="header-section-number">5.3</span> 交叉验证优化训练</a></li>
  <li><a href="#模型的选择和快速构建" id="toc-模型的选择和快速构建" class="nav-link" data-scroll-target="#模型的选择和快速构建"><span class="header-section-number">5.4</span> 模型的选择和快速构建</a></li>
  </ul></li>
  <li><a href="#homework" id="toc-homework" class="nav-link" data-scroll-target="#homework"><span class="header-section-number">6</span> Homework</a></li>
  <li><a href="#session-information" id="toc-session-information" class="nav-link" data-scroll-target="#session-information"><span class="header-section-number">7</span> Session information</a></li>
  </ul>
</nav>
</div>
<main class="content" id="quarto-document-content">

<header id="title-block-header" class="quarto-title-block default">
<div class="quarto-title">
<div class="quarto-title-block"><div><h1 class="title">医学生入门机器学习-tidymodels基础与流程</h1><button type="button" class="btn code-tools-button dropdown-toggle" id="quarto-code-tools-menu" data-bs-toggle="dropdown" aria-expanded="false"><i class="bi"></i> Code</button><ul class="dropdown-menu dropdown-menu-end" aria-labelelledby="quarto-code-tools-menu"><li><a id="quarto-show-all-code" class="dropdown-item" href="javascript:void(0)" role="button">Show All Code</a></li><li><a id="quarto-hide-all-code" class="dropdown-item" href="javascript:void(0)" role="button">Hide All Code</a></li><li><hr class="dropdown-divider"></li><li><a id="quarto-view-source" class="dropdown-item" href="javascript:void(0)" role="button">View Source</a></li></ul></div></div>
</div>


<div class="quarto-title-meta-author">
  <div class="quarto-title-meta-heading">Author</div>
  <div class="quarto-title-meta-heading">Affiliations</div>
  
    <div class="quarto-title-meta-contents">
    <p class="author">梁昊 </p>
  </div>
  <div class="quarto-title-meta-contents">
        <p class="affiliation">
            医咖会
          </p>
        <p class="affiliation">
            湖南中医药大学
          </p>
      </div>
  </div>

<div class="quarto-title-meta">

      
  
    
  </div>
  


</header>


<section id="写给医学伙伴的悄悄话" class="level2" data-number="1">
<h2 data-number="1" class="anchored" data-anchor-id="写给医学伙伴的悄悄话"><span class="header-section-number">1</span> 写给医学伙伴的悄悄话</h2>
<p>我是来自双非高校的一名普通老师，在探索医学和计算机学科的交叉过程中，走了很多弯路，这些路我不希望大家重走，而是直接迈入学习的<strong>快车道</strong>。</p>
<p>现今机器学习领域已经得到了极大发展，各种机器学习的工具和包层出不穷，自动化机器学习(auto machine learning，AutoML)的理念已经深入人心，无论什么领域，都应该专注<strong>业务本身</strong>，而非代码或算法，那是程序员和数学家的事，我们要做的就是如何用AutoML解决我们医学上的问题，而不是让编程和数学基础成为你解决科学问题的绊脚石。</p>
<p>机器学习领域Python和R已经是毫无争议的最佳编程语言。这其中tidymodels是R在AutoML领域的集大成者，学会了就能快速构建完整的机器学习。</p>
</section>
<section id="医学数据" class="level2" data-number="2">
<h2 data-number="2" class="anchored" data-anchor-id="医学数据"><span class="header-section-number">2</span> 医学数据</h2>
<p>关于机器学习的很多基础概念，推荐大家到<a href="https://www.showmeai.tech/article-detail/185">ShowMeAI知识社区-图解机器学习 | 机器学习基础知识</a>查看。许多基础的概念，我不会在这里解释，也是督促大家自学。</p>
<p>我们首先要认识到，不同的数据，处理和分析的方式不同，就像杀苍蝇用手枪，如果用错了工具，任务是无法完成的。</p>
<p>医学常见的数据有哪些？</p>
<section id="文本数据" class="level3" data-number="2.1">
<h3 data-number="2.1" class="anchored" data-anchor-id="文本数据"><span class="header-section-number">2.1</span> 文本数据</h3>
<p>在这里，我把文本形式存储的数据全部叫文本数据。这些数据，有些是按照事先约定好的形式和格式采集和录入而形成的表格型数据（像excel），也有普通的一本书、一篇文章这样的纯粹文字数据。其中，表格型数据（dataframe）是我们使用最多，最需要掌握的数据类型。</p>
<ol type="1">
<li>表格数据（dataframe）</li>
</ol>
<p><code>dataframe</code> 顾名思义，也叫方形数据（Rectangular Data）。Python（pandas包）和R都将这种数据称为dataframe，也是最常见的数据对象。 在R中，还有<code>tibble</code>和<code>data.table</code>这类<code>dataframe</code>的变种，本质上还是方形数据，只不过用来处理的包和风格不太相同。</p>
<div class="callout callout-style-default callout-note callout-titled">
<div class="callout-header d-flex align-content-center">
<div class="callout-icon-container">
<i class="callout-icon"></i>
</div>
<div class="callout-title-container flex-fill">
Note
</div>
</div>
<div class="callout-body-container callout-body">
<p>tidymodels能够分析的主要是dataframe。</p>
</div>
</div>
<p>下面的表格数据就是一个<code>dataframe</code>例子</p>
<div class="cell">
<details open="" class="code-fold">
<summary>Code</summary>
<div class="sourceCode cell-code" id="cb1"><pre class="sourceCode numberSource r number-lines code-with-copy"><code class="sourceCode r"><span id="cb1-1"><a href="#cb1-1"></a><span class="fu">head</span>(esoph,<span class="dv">8</span>)</span></code><button title="Copy to Clipboard" class="code-copy-button"><i class="bi"></i></button></pre></div>
</details>
<div class="cell-output-display">
<div class="kable-table">
<table class="caption-top table table-sm table-striped small">
<thead>
<tr class="header">
<th style="text-align: left;">agegp</th>
<th style="text-align: left;">alcgp</th>
<th style="text-align: left;">tobgp</th>
<th style="text-align: right;">ncases</th>
<th style="text-align: right;">ncontrols</th>
</tr>
</thead>
<tbody>
<tr class="odd">
<td style="text-align: left;">25-34</td>
<td style="text-align: left;">0-39g/day</td>
<td style="text-align: left;">0-9g/day</td>
<td style="text-align: right;">0</td>
<td style="text-align: right;">40</td>
</tr>
<tr class="even">
<td style="text-align: left;">25-34</td>
<td style="text-align: left;">0-39g/day</td>
<td style="text-align: left;">10-19</td>
<td style="text-align: right;">0</td>
<td style="text-align: right;">10</td>
</tr>
<tr class="odd">
<td style="text-align: left;">25-34</td>
<td style="text-align: left;">0-39g/day</td>
<td style="text-align: left;">20-29</td>
<td style="text-align: right;">0</td>
<td style="text-align: right;">6</td>
</tr>
<tr class="even">
<td style="text-align: left;">25-34</td>
<td style="text-align: left;">0-39g/day</td>
<td style="text-align: left;">30+</td>
<td style="text-align: right;">0</td>
<td style="text-align: right;">5</td>
</tr>
<tr class="odd">
<td style="text-align: left;">25-34</td>
<td style="text-align: left;">40-79</td>
<td style="text-align: left;">0-9g/day</td>
<td style="text-align: right;">0</td>
<td style="text-align: right;">27</td>
</tr>
<tr class="even">
<td style="text-align: left;">25-34</td>
<td style="text-align: left;">40-79</td>
<td style="text-align: left;">10-19</td>
<td style="text-align: right;">0</td>
<td style="text-align: right;">7</td>
</tr>
<tr class="odd">
<td style="text-align: left;">25-34</td>
<td style="text-align: left;">40-79</td>
<td style="text-align: left;">20-29</td>
<td style="text-align: right;">0</td>
<td style="text-align: right;">4</td>
</tr>
<tr class="even">
<td style="text-align: left;">25-34</td>
<td style="text-align: left;">40-79</td>
<td style="text-align: left;">30+</td>
<td style="text-align: right;">0</td>
<td style="text-align: right;">7</td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
<ol start="2" type="1">
<li>纯粹文本Plain text</li>
</ol>
<p>纯文本，因为它纯了，就是普通不加任何清洗和修改的自然文字段落。</p>
</section>
<section id="其他数据" class="level3" data-number="2.2">
<h3 data-number="2.2" class="anchored" data-anchor-id="其他数据"><span class="header-section-number">2.2</span> 其他数据</h3>
<ul>
<li><p>时间序列Time series data</p>
<p>大部分信号处理都是这类数据，比如心电图、股票、声波。</p></li>
<li><p>空间数据Spatial data</p>
<p>地图、导航类似的数据。</p></li>
<li><p>图数据Graph (or network) data</p>
<blockquote class="blockquote">
<p>In computer science and information technology, the term graph typically refers to a depiction of the connections among entities, and to the underlying data structure.在计算机科学和信息技术中，术语”图”通常指实体之间的连接和底层数据结构的描述。如图神经网络。平时我们看到的知识图谱就属于这一类。</p>
</blockquote></li>
<li><p>图像和视频数据image data and video data</p></li>
</ul>
</section>
</section>
<section id="机器学习类型和业务逻辑" class="level2" data-number="3">
<h2 data-number="3" class="anchored" data-anchor-id="机器学习类型和业务逻辑"><span class="header-section-number">3</span> 机器学习类型和业务逻辑</h2>
<p>在确定我们需要的机器学习类型时，我们要根据我们的医学业务来明确以下问题。</p>
<ol type="1">
<li><p>监督学习（预测的目标已做好标记，如死亡、患病）还是非监督学习（目标情况不清楚，比如哪两个中药搭配最常见）。</p></li>
<li><p>明确哪个是要预测的目标Y。</p></li>
<li><p>如果是监督学习，目标Y是分类问题，还是回归问题，如<a href="#fig-regressionclassification" class="quarto-xref">Figure&nbsp;1</a>。</p></li>
</ol>
<div id="fig-regressionclassification" class="quarto-figure quarto-figure-center quarto-float anchored">
<figure class="quarto-float quarto-float-fig figure">
<div aria-describedby="fig-regressionclassification-caption-0ceaefa1-69ba-4598-a22c-09a6ac19f8ca">
<img src="./images/regression-vs.-classification.png" class="img-fluid figure-img">
</div>
<figcaption class="quarto-float-caption-bottom quarto-float-caption quarto-float-fig" id="fig-regressionclassification-caption-0ceaefa1-69ba-4598-a22c-09a6ac19f8ca">
Figure&nbsp;1: Regression vs Classification in Machine Learning
</figcaption>
</figure>
</div>
<div class="callout callout-style-default callout-note callout-titled">
<div class="callout-header d-flex align-content-center">
<div class="callout-icon-container">
<i class="callout-icon"></i>
</div>
<div class="callout-title-container flex-fill">
Note
</div>
</div>
<div class="callout-body-container callout-body">
<ul>
<li>In the regression problem, Y is numeric (e.g price, blood pressure).</li>
<li>In the classification problem, Y takes values in a finite, unordered set (survived/died, cancer class of tissue sample).</li>
</ul>
</div>
</div>
<p>表格数据中列的列是<code>variable</code>。作为医学研究，我们可以理解为研究对象的属性(attribute)，比如，病人的年龄、性别、收入等。<code>variable</code>是根据你要做的研究业务需求而设立的，比如最常见的RCT研究，不同的治疗方法或者说治疗组+对照组一起构成了group这个<code>variable</code>(列)。<code>variable</code>在计算机领域也被称为字段。</p>
<p>variable根据业务需要，还可分为两类</p>
<ul>
<li>自变量（X），也被称为input, predictor, (independent) variable, regressor, covariate, feature, explanatory variable</li>
<li>因变量（Y），也被称为dependent variable, response, outcome, target, output, response variable</li>
</ul>
<p>比如，下面这个数据，如果我们把是否早产<code>premature</code>作为要预测的Y（response），其他变量就可以定为X（predictors）</p>
<div class="cell">
<details open="" class="code-fold">
<summary>Code</summary>
<div class="sourceCode cell-code" id="cb2"><pre class="sourceCode numberSource r number-lines code-with-copy"><code class="sourceCode r"><span id="cb2-1"><a href="#cb2-1"></a><span class="fu">load</span>(<span class="st">"./datasets/births.rda"</span>) </span>
<span id="cb2-2"><a href="#cb2-2"></a><span class="fu">head</span>(births,<span class="dv">10</span>) </span></code><button title="Copy to Clipboard" class="code-copy-button"><i class="bi"></i></button></pre></div>
</details>
<div id="tbl-birth" class="cell quarto-float anchored">
<figure class="quarto-float quarto-float-tbl figure">
<figcaption class="quarto-float-caption-top quarto-float-caption quarto-float-tbl" id="tbl-birth-caption-0ceaefa1-69ba-4598-a22c-09a6ac19f8ca">
Table&nbsp;1: Birth table
</figcaption>
<div aria-describedby="tbl-birth-caption-0ceaefa1-69ba-4598-a22c-09a6ac19f8ca">
<div class="cell-output-display">
<div class="kable-table">
<table class="do-not-create-environment cell caption-top table table-sm table-striped small">
<colgroup>
<col style="width: 8%">
<col style="width: 8%">
<col style="width: 8%">
<col style="width: 14%">
<col style="width: 10%">
<col style="width: 10%">
<col style="width: 10%">
<col style="width: 13%">
<col style="width: 14%">
</colgroup>
<thead>
<tr class="header">
<th style="text-align: right;">f_age</th>
<th style="text-align: right;">m_age</th>
<th style="text-align: right;">weeks</th>
<th style="text-align: left;">premature</th>
<th style="text-align: right;">visits</th>
<th style="text-align: right;">gained</th>
<th style="text-align: right;">weight</th>
<th style="text-align: left;">sex_baby</th>
<th style="text-align: left;">smoke</th>
</tr>
</thead>
<tbody>
<tr class="odd">
<td style="text-align: right;">31</td>
<td style="text-align: right;">30</td>
<td style="text-align: right;">39</td>
<td style="text-align: left;">full term</td>
<td style="text-align: right;">13</td>
<td style="text-align: right;">1</td>
<td style="text-align: right;">6.88</td>
<td style="text-align: left;">male</td>
<td style="text-align: left;">smoker</td>
</tr>
<tr class="even">
<td style="text-align: right;">34</td>
<td style="text-align: right;">36</td>
<td style="text-align: right;">39</td>
<td style="text-align: left;">full term</td>
<td style="text-align: right;">5</td>
<td style="text-align: right;">35</td>
<td style="text-align: right;">7.69</td>
<td style="text-align: left;">male</td>
<td style="text-align: left;">nonsmoker</td>
</tr>
<tr class="odd">
<td style="text-align: right;">36</td>
<td style="text-align: right;">35</td>
<td style="text-align: right;">40</td>
<td style="text-align: left;">full term</td>
<td style="text-align: right;">12</td>
<td style="text-align: right;">29</td>
<td style="text-align: right;">8.88</td>
<td style="text-align: left;">male</td>
<td style="text-align: left;">nonsmoker</td>
</tr>
<tr class="even">
<td style="text-align: right;">41</td>
<td style="text-align: right;">40</td>
<td style="text-align: right;">40</td>
<td style="text-align: left;">full term</td>
<td style="text-align: right;">13</td>
<td style="text-align: right;">30</td>
<td style="text-align: right;">9.00</td>
<td style="text-align: left;">female</td>
<td style="text-align: left;">nonsmoker</td>
</tr>
<tr class="odd">
<td style="text-align: right;">42</td>
<td style="text-align: right;">37</td>
<td style="text-align: right;">40</td>
<td style="text-align: left;">full term</td>
<td style="text-align: right;">NA</td>
<td style="text-align: right;">10</td>
<td style="text-align: right;">7.94</td>
<td style="text-align: left;">male</td>
<td style="text-align: left;">nonsmoker</td>
</tr>
<tr class="even">
<td style="text-align: right;">37</td>
<td style="text-align: right;">28</td>
<td style="text-align: right;">40</td>
<td style="text-align: left;">full term</td>
<td style="text-align: right;">12</td>
<td style="text-align: right;">35</td>
<td style="text-align: right;">8.25</td>
<td style="text-align: left;">male</td>
<td style="text-align: left;">smoker</td>
</tr>
<tr class="odd">
<td style="text-align: right;">35</td>
<td style="text-align: right;">35</td>
<td style="text-align: right;">28</td>
<td style="text-align: left;">premie</td>
<td style="text-align: right;">6</td>
<td style="text-align: right;">29</td>
<td style="text-align: right;">1.63</td>
<td style="text-align: left;">female</td>
<td style="text-align: left;">nonsmoker</td>
</tr>
<tr class="even">
<td style="text-align: right;">28</td>
<td style="text-align: right;">21</td>
<td style="text-align: right;">35</td>
<td style="text-align: left;">premie</td>
<td style="text-align: right;">9</td>
<td style="text-align: right;">15</td>
<td style="text-align: right;">5.50</td>
<td style="text-align: left;">female</td>
<td style="text-align: left;">smoker</td>
</tr>
<tr class="odd">
<td style="text-align: right;">22</td>
<td style="text-align: right;">20</td>
<td style="text-align: right;">32</td>
<td style="text-align: left;">premie</td>
<td style="text-align: right;">5</td>
<td style="text-align: right;">40</td>
<td style="text-align: right;">2.69</td>
<td style="text-align: left;">male</td>
<td style="text-align: left;">smoker</td>
</tr>
<tr class="even">
<td style="text-align: right;">36</td>
<td style="text-align: right;">25</td>
<td style="text-align: right;">40</td>
<td style="text-align: left;">full term</td>
<td style="text-align: right;">13</td>
<td style="text-align: right;">34</td>
<td style="text-align: right;">8.75</td>
<td style="text-align: left;">female</td>
<td style="text-align: left;">nonsmoker</td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
</figure>
</div>
</div>
</section>
<section id="机器学习的流程" class="level2" data-number="4">
<h2 data-number="4" class="anchored" data-anchor-id="机器学习的流程"><span class="header-section-number">4</span> 机器学习的流程</h2>
<div id="fig-workflow" class="quarto-figure quarto-figure-center quarto-float anchored">
<figure class="quarto-float quarto-float-fig figure">
<div aria-describedby="fig-workflow-caption-0ceaefa1-69ba-4598-a22c-09a6ac19f8ca">
<img src="./images/workflow.png" class="img-fluid figure-img">
</div>
<figcaption class="quarto-float-caption-bottom quarto-float-caption quarto-float-fig" id="fig-workflow-caption-0ceaefa1-69ba-4598-a22c-09a6ac19f8ca">
Figure&nbsp;2: workflow of machine learning
</figcaption>
</figure>
</div>
<p>数据准备(包含预处理和特征工程) -&gt; 数据拆分-&gt; 选择模型 -&gt; 训练 -&gt; 评价 -&gt; 调参 -&gt; 再评价 -&gt; 应用(predict), <a href="#fig-workflow" class="quarto-xref">Figure&nbsp;2</a></p>
<blockquote class="blockquote">
<p>“The tidymodels framework is a collection of packages for modeling and machine learning using tidyverse principles.” - tidymodels.org</p>
</blockquote>
<p>tidymodels 是用于数据科学建模的一系列的包。安装方法<code>install.packages("tidymodels")</code></p>
<p><code>tidymodels</code>包含了一系列的R包，这些包括。</p>
<ol type="1">
<li>rsample 高效的数据拆分和重采样</li>
<li>parsnip 统一的模型接口，可用于尝试一系列模型，而不会陷入底层包的语法细节</li>
<li>recipes 是用于数据预处理和特征工程工具的整洁接口</li>
<li>workflow 将预处理、建模和后处理集合在一起,是最关键的包</li>
<li>tune 可帮助您优化模型的超参数</li>
<li>dials 创建和管理调整参数和参数网格与tune配合使用</li>
<li>yardstick 使用性能指标来衡量模型的效果</li>
<li>broom 将常见统计结果中的信息转换为用户友好、结构化的格式。</li>
</ol>
<p>以上这些包在加载<code>tidymodels</code>的时候会一起加载，还有很多其他有用的工具需要手动进行加载。</p>
<p>还有些其他的包，大家也可以看看<a href="https://tidymodels.r-universe.dev/builds">R packages by tidymodels</a></p>
<div id="fig-flowpackage" class="lightbox quarto-figure quarto-figure-center quarto-float anchored">
<figure class="quarto-float quarto-float-fig figure">
<div aria-describedby="fig-flowpackage-caption-0ceaefa1-69ba-4598-a22c-09a6ac19f8ca">
<a href="./images/flowpackage.png" class="lightbox" data-gallery="quarto-lightbox-gallery-1" data-glightbox="description: .lightbox-desc-1"><img src="./images/flowpackage.png" class="img-fluid figure-img"></a>
</div>
<figcaption class="quarto-float-caption-bottom quarto-float-caption quarto-float-fig" id="fig-flowpackage-caption-0ceaefa1-69ba-4598-a22c-09a6ac19f8ca">
Figure&nbsp;3: workflow of packages
</figcaption>
</figure>
</div>
<p><code>tidymodels</code>究竟怎么构建这个机器学习的过程,从这个<a href="#fig-flowpackage" class="quarto-xref">Figure&nbsp;3</a>中,我们可以根据对应的包略见一二。</p>
<p>正所谓大道至简，我今天用一句话来阐释<code>tidymodels</code>的监督机器学习实施步骤：</p>
<p>确定好你要预测的目标（response，regression or classification）， <code>rsample</code>按照训练需要将数据进行分割，<code>recipes</code>对数据进行预处理和特征工程，<code>parsnip</code>选定一个模型和引擎，<code>yardstick</code>确定模型的评价指标， <code>workflow</code>将这些统筹起来，然后开始训练，评价反馈，用<code>tune</code>调整模型并获得最佳模型，最终在test set 做最终模型评价。</p>
</section>
<section id="tidymodels实践" class="level2" data-number="5">
<h2 data-number="5" class="anchored" data-anchor-id="tidymodels实践"><span class="header-section-number">5</span> tidymodels实践</h2>
<p>下面和我一起来分步完成一次机器学习实践吧。</p>
<section id="载入package" class="level3" data-number="5.1">
<h3 data-number="5.1" class="anchored" data-anchor-id="载入package"><span class="header-section-number">5.1</span> 载入package</h3>
<div class="cell">
<details open="" class="code-fold">
<summary>Code</summary>
<div class="sourceCode cell-code" id="cb3"><pre class="sourceCode numberSource r number-lines code-with-copy"><code class="sourceCode r"><span id="cb3-1"><a href="#cb3-1"></a><span class="fu">library</span>(tidymodels)</span>
<span id="cb3-2"><a href="#cb3-2"></a><span class="fu">library</span>(usemodels)</span>
<span id="cb3-3"><a href="#cb3-3"></a><span class="fu">library</span>(dplyr)</span>
<span id="cb3-4"><a href="#cb3-4"></a><span class="fu">library</span>(readr)</span>
<span id="cb3-5"><a href="#cb3-5"></a><span class="fu">library</span>(magrittr)</span></code><button title="Copy to Clipboard" class="code-copy-button"><i class="bi"></i></button></pre></div>
</details>
</div>
</section>
<section id="tidymodels流程初体验" class="level3" data-number="5.2">
<h3 data-number="5.2" class="anchored" data-anchor-id="tidymodels流程初体验"><span class="header-section-number">5.2</span> tidymodels流程初体验</h3>
<div class="cell">
<details open="" class="code-fold">
<summary>Code</summary>
<div class="sourceCode cell-code" id="cb4"><pre class="sourceCode numberSource r number-lines code-with-copy"><code class="sourceCode r"><span id="cb4-1"><a href="#cb4-1"></a><span class="co">#读取数据</span></span>
<span id="cb4-2"><a href="#cb4-2"></a>strokedf <span class="ot">&lt;-</span> <span class="fu">read_csv</span>(<span class="st">"./datasets/stroke_data.csv"</span>, <span class="at">col_types =</span> <span class="fu">cols</span>(<span class="at">stroke =</span> <span class="st">"f"</span>) ) </span>
<span id="cb4-3"><a href="#cb4-3"></a><span class="fu">set.seed</span>(<span class="dv">123</span>)</span>
<span id="cb4-4"><a href="#cb4-4"></a></span>
<span id="cb4-5"><a href="#cb4-5"></a><span class="co">#按照8：2对数据进行拆分Training，test</span></span>
<span id="cb4-6"><a href="#cb4-6"></a>data_split <span class="ot">&lt;-</span> <span class="fu">initial_split</span>(strokedf, </span>
<span id="cb4-7"><a href="#cb4-7"></a>                           <span class="at">prop =</span> <span class="fl">0.80</span>, </span>
<span id="cb4-8"><a href="#cb4-8"></a>                           <span class="at">strata =</span> stroke)</span>
<span id="cb4-9"><a href="#cb4-9"></a>train_stroke <span class="ot">&lt;-</span> <span class="fu">training</span>(data_split) </span>
<span id="cb4-10"><a href="#cb4-10"></a>test_stroke <span class="ot">&lt;-</span> <span class="fu">testing</span>(data_split)</span>
<span id="cb4-11"><a href="#cb4-11"></a></span>
<span id="cb4-12"><a href="#cb4-12"></a><span class="co">#数据预处理</span></span>
<span id="cb4-13"><a href="#cb4-13"></a>stroke_res <span class="ot">&lt;-</span> <span class="fu">recipe</span>(stroke <span class="sc">~</span> ., <span class="at">data =</span> train_stroke) <span class="sc">%&gt;%</span> </span>
<span id="cb4-14"><a href="#cb4-14"></a>  <span class="fu">update_role</span>(id, <span class="at">new_role =</span> <span class="st">"ID"</span>) <span class="sc">%&gt;%</span> </span>
<span id="cb4-15"><a href="#cb4-15"></a>  <span class="fu">step_impute_bag</span>(<span class="fu">all_predictors</span>()) <span class="sc">%&gt;%</span> </span>
<span id="cb4-16"><a href="#cb4-16"></a>  <span class="fu">step_normalize</span>(<span class="fu">all_numeric_predictors</span>()) <span class="sc">%&gt;%</span> </span>
<span id="cb4-17"><a href="#cb4-17"></a>  <span class="fu">step_zv</span>(<span class="fu">all_predictors</span>()) </span>
<span id="cb4-18"><a href="#cb4-18"></a></span>
<span id="cb4-19"><a href="#cb4-19"></a><span class="co">#设定模型</span></span>
<span id="cb4-20"><a href="#cb4-20"></a>lr_mod <span class="ot">&lt;-</span> </span>
<span id="cb4-21"><a href="#cb4-21"></a>  <span class="fu">logistic_reg</span>() <span class="sc">%&gt;%</span> <span class="co">#逻辑回归</span></span>
<span id="cb4-22"><a href="#cb4-22"></a>  <span class="fu">set_engine</span>(<span class="st">"glm"</span>)</span>
<span id="cb4-23"><a href="#cb4-23"></a></span>
<span id="cb4-24"><a href="#cb4-24"></a><span class="co">#workflow集成</span></span>
<span id="cb4-25"><a href="#cb4-25"></a>stroke_flow <span class="ot">&lt;-</span> </span>
<span id="cb4-26"><a href="#cb4-26"></a>  <span class="fu">workflow</span>() <span class="sc">%&gt;%</span> </span>
<span id="cb4-27"><a href="#cb4-27"></a>  <span class="fu">add_model</span>(lr_mod) <span class="sc">%&gt;%</span> </span>
<span id="cb4-28"><a href="#cb4-28"></a>  <span class="fu">add_recipe</span>(stroke_res)</span>
<span id="cb4-29"><a href="#cb4-29"></a>  </span>
<span id="cb4-30"><a href="#cb4-30"></a><span class="co">#训练模型（拟合）</span></span>
<span id="cb4-31"><a href="#cb4-31"></a>stroke_fit <span class="ot">&lt;-</span> </span>
<span id="cb4-32"><a href="#cb4-32"></a>  stroke_flow <span class="sc">%&gt;%</span> </span>
<span id="cb4-33"><a href="#cb4-33"></a>  <span class="fu">fit</span>(<span class="at">data =</span> train_stroke)</span>
<span id="cb4-34"><a href="#cb4-34"></a></span>
<span id="cb4-35"><a href="#cb4-35"></a><span class="co">#测试集评估</span></span>
<span id="cb4-36"><a href="#cb4-36"></a>stroke_aug <span class="ot">&lt;-</span> </span>
<span id="cb4-37"><a href="#cb4-37"></a>  <span class="fu">augment</span>(stroke_fit, test_stroke) <span class="sc">%&gt;%</span> </span>
<span id="cb4-38"><a href="#cb4-38"></a>  <span class="fu">select</span>(stroke,.pred_1,.pred_class)</span>
<span id="cb4-39"><a href="#cb4-39"></a></span>
<span id="cb4-40"><a href="#cb4-40"></a>stroke_aug <span class="sc">%&gt;%</span> </span>
<span id="cb4-41"><a href="#cb4-41"></a>  <span class="fu">roc_curve</span>(<span class="at">truth =</span> stroke, .pred_1) <span class="sc">%&gt;%</span> <span class="co">#ROC曲线</span></span>
<span id="cb4-42"><a href="#cb4-42"></a>  <span class="fu">autoplot</span>()</span></code><button title="Copy to Clipboard" class="code-copy-button"><i class="bi"></i></button></pre></div>
</details>
<div class="cell-output-display">
<div>
<figure class="figure">
<p><img src="00.Preface_files/figure-html/unnamed-chunk-4-1.png" class="img-fluid figure-img" width="672"></p>
</figure>
</div>
</div>
<details open="" class="code-fold">
<summary>Code</summary>
<div class="sourceCode cell-code" id="cb5"><pre class="sourceCode numberSource r number-lines code-with-copy"><code class="sourceCode r"><span id="cb5-1"><a href="#cb5-1"></a>stroke_aug <span class="sc">%&gt;%</span> </span>
<span id="cb5-2"><a href="#cb5-2"></a>  <span class="fu">conf_mat</span>(stroke, .pred_class) <span class="sc">%&gt;%</span> <span class="co">#混淆矩阵</span></span>
<span id="cb5-3"><a href="#cb5-3"></a>  <span class="fu">autoplot</span>(<span class="at">type =</span> <span class="st">"heatmap"</span>)</span></code><button title="Copy to Clipboard" class="code-copy-button"><i class="bi"></i></button></pre></div>
</details>
<div class="cell-output-display">
<div>
<figure class="figure">
<p><img src="00.Preface_files/figure-html/unnamed-chunk-4-2.png" class="img-fluid figure-img" width="672"></p>
</figure>
</div>
</div>
<details open="" class="code-fold">
<summary>Code</summary>
<div class="sourceCode cell-code" id="cb6"><pre class="sourceCode numberSource r number-lines code-with-copy"><code class="sourceCode r"><span id="cb6-1"><a href="#cb6-1"></a>stroke_aug <span class="sc">%&gt;%</span> </span>
<span id="cb6-2"><a href="#cb6-2"></a>  <span class="fu">roc_auc</span>(<span class="at">truth =</span> stroke, .pred_1) <span class="co">#AUC</span></span></code><button title="Copy to Clipboard" class="code-copy-button"><i class="bi"></i></button></pre></div>
</details>
<div class="cell-output-display">
<div class="kable-table">
<table class="caption-top table table-sm table-striped small">
<thead>
<tr class="header">
<th style="text-align: left;">.metric</th>
<th style="text-align: left;">.estimator</th>
<th style="text-align: right;">.estimate</th>
</tr>
</thead>
<tbody>
<tr class="odd">
<td style="text-align: left;">roc_auc</td>
<td style="text-align: left;">binary</td>
<td style="text-align: right;">0.8391237</td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
</section>
<section id="交叉验证优化训练" class="level3" data-number="5.3">
<h3 data-number="5.3" class="anchored" data-anchor-id="交叉验证优化训练"><span class="header-section-number">5.3</span> 交叉验证优化训练</h3>
<p>刚刚我们流程过了一遍，但有些同志可能会纳闷，好像训练的时候数据集没有划分啊！并没有Validation set这个。 下面我们就以这种方式来训练，并且我们要提到一种叫交叉验证的训练方式(Cross-Validation)。什么是交叉验证，我们看<a href="#fig-folds" class="quarto-xref">Figure&nbsp;4</a>，这就是一个典型的5折交叉验证，将Training set划分成5份，然后每1份都做一次Validation set，其余作为Training set，反复训练5次，取平均值。</p>
<div id="fig-folds" class="lightbox quarto-figure quarto-figure-center quarto-float anchored">
<figure class="quarto-float quarto-float-fig figure">
<div aria-describedby="fig-folds-caption-0ceaefa1-69ba-4598-a22c-09a6ac19f8ca">
<a href="./images/folds_cv.jpg" class="lightbox" data-gallery="quarto-lightbox-gallery-2" data-glightbox="description: .lightbox-desc-2"><img src="./images/folds_cv.jpg" class="img-fluid figure-img"></a>
</div>
<figcaption class="quarto-float-caption-bottom quarto-float-caption quarto-float-fig" id="fig-folds-caption-0ceaefa1-69ba-4598-a22c-09a6ac19f8ca">
Figure&nbsp;4: 5折交叉验证
</figcaption>
</figure>
</div>
<p>k 折交叉验证对 k 个不同分组训练的结果进行平均来减少方差，因此模型的性能对数据的划分就不那么敏感，对数据的使用也会更充分，模型评估结果更加稳定。下面我们来以随机森林机器模型，采用5折交叉验证来实现一个新的训练。</p>
<div class="cell">
<details open="" class="code-fold">
<summary>Code</summary>
<div class="sourceCode cell-code" id="cb7"><pre class="sourceCode numberSource r number-lines code-with-copy"><code class="sourceCode r"><span id="cb7-1"><a href="#cb7-1"></a><span class="co">#读取数据</span></span>
<span id="cb7-2"><a href="#cb7-2"></a>strokedf <span class="ot">&lt;-</span> <span class="fu">read_csv</span>(<span class="st">"./datasets/stroke_data.csv"</span>, <span class="at">col_types =</span> <span class="fu">cols</span>(<span class="at">stroke =</span> <span class="st">"f"</span>) ) </span>
<span id="cb7-3"><a href="#cb7-3"></a><span class="fu">set.seed</span>(<span class="dv">123</span>)</span>
<span id="cb7-4"><a href="#cb7-4"></a></span>
<span id="cb7-5"><a href="#cb7-5"></a><span class="co">#按照8：2对数据进行拆分Training，test</span></span>
<span id="cb7-6"><a href="#cb7-6"></a>data_split <span class="ot">&lt;-</span> <span class="fu">initial_split</span>(strokedf, </span>
<span id="cb7-7"><a href="#cb7-7"></a>                           <span class="at">prop =</span> <span class="fl">0.80</span>, </span>
<span id="cb7-8"><a href="#cb7-8"></a>                           <span class="at">strata =</span> stroke)</span>
<span id="cb7-9"><a href="#cb7-9"></a>train_stroke <span class="ot">&lt;-</span> <span class="fu">training</span>(data_split) </span>
<span id="cb7-10"><a href="#cb7-10"></a>test_stroke <span class="ot">&lt;-</span> <span class="fu">testing</span>(data_split)</span>
<span id="cb7-11"><a href="#cb7-11"></a></span>
<span id="cb7-12"><a href="#cb7-12"></a><span class="co">#数据预处理</span></span>
<span id="cb7-13"><a href="#cb7-13"></a>stroke_res <span class="ot">&lt;-</span> <span class="fu">recipe</span>(stroke <span class="sc">~</span> ., <span class="at">data =</span> train_stroke) <span class="sc">%&gt;%</span> </span>
<span id="cb7-14"><a href="#cb7-14"></a>  <span class="fu">update_role</span>(id, <span class="at">new_role =</span> <span class="st">"ID"</span>) <span class="sc">%&gt;%</span> </span>
<span id="cb7-15"><a href="#cb7-15"></a>  <span class="fu">step_impute_bag</span>(<span class="fu">all_predictors</span>()) <span class="sc">%&gt;%</span> </span>
<span id="cb7-16"><a href="#cb7-16"></a>  <span class="fu">step_normalize</span>(<span class="fu">all_numeric_predictors</span>()) <span class="sc">%&gt;%</span> </span>
<span id="cb7-17"><a href="#cb7-17"></a>  <span class="fu">step_zv</span>(<span class="fu">all_predictors</span>()) </span>
<span id="cb7-18"><a href="#cb7-18"></a></span>
<span id="cb7-19"><a href="#cb7-19"></a><span class="co">#设定模型</span></span>
<span id="cb7-20"><a href="#cb7-20"></a>rf_mod <span class="ot">&lt;-</span> </span>
<span id="cb7-21"><a href="#cb7-21"></a>  <span class="fu">rand_forest</span>(<span class="at">trees =</span> <span class="dv">1000</span>) <span class="sc">%&gt;%</span> <span class="co">#随机森林模型</span></span>
<span id="cb7-22"><a href="#cb7-22"></a>  <span class="fu">set_engine</span>(<span class="st">"ranger"</span>) <span class="sc">%&gt;%</span> </span>
<span id="cb7-23"><a href="#cb7-23"></a>  <span class="fu">set_mode</span>(<span class="st">"classification"</span>)</span>
<span id="cb7-24"><a href="#cb7-24"></a></span>
<span id="cb7-25"><a href="#cb7-25"></a><span class="co">#workflow集成</span></span>
<span id="cb7-26"><a href="#cb7-26"></a>stroke_flow <span class="ot">&lt;-</span> </span>
<span id="cb7-27"><a href="#cb7-27"></a>  <span class="fu">workflow</span>() <span class="sc">%&gt;%</span> </span>
<span id="cb7-28"><a href="#cb7-28"></a>  <span class="fu">add_recipe</span>(stroke_res)<span class="sc">%&gt;%</span> </span>
<span id="cb7-29"><a href="#cb7-29"></a>  <span class="fu">add_model</span>(rf_mod)</span>
<span id="cb7-30"><a href="#cb7-30"></a>  </span>
<span id="cb7-31"><a href="#cb7-31"></a>  </span>
<span id="cb7-32"><a href="#cb7-32"></a><span class="co"># Cross validation</span></span>
<span id="cb7-33"><a href="#cb7-33"></a><span class="fu">set.seed</span>(<span class="dv">123</span>)</span>
<span id="cb7-34"><a href="#cb7-34"></a>cv_folds <span class="ot">&lt;-</span> </span>
<span id="cb7-35"><a href="#cb7-35"></a>  <span class="fu">vfold_cv</span>(train_stroke, <span class="at">v =</span> <span class="dv">5</span>)</span>
<span id="cb7-36"><a href="#cb7-36"></a>  </span>
<span id="cb7-37"><a href="#cb7-37"></a><span class="co">#训练模型（拟合）</span></span>
<span id="cb7-38"><a href="#cb7-38"></a>rf_res <span class="ot">&lt;-</span> stroke_flow <span class="sc">%&gt;%</span></span>
<span id="cb7-39"><a href="#cb7-39"></a>  <span class="fu">fit_resamples</span>(cv_folds)</span>
<span id="cb7-40"><a href="#cb7-40"></a></span>
<span id="cb7-41"><a href="#cb7-41"></a><span class="fu">collect_metrics</span>(rf_res, <span class="at">summarize =</span> <span class="cn">FALSE</span>)</span></code><button title="Copy to Clipboard" class="code-copy-button"><i class="bi"></i></button></pre></div>
</details>
<div class="cell-output-display">
<div class="kable-table">
<table class="caption-top table table-sm table-striped small">
<thead>
<tr class="header">
<th style="text-align: left;">id</th>
<th style="text-align: left;">.metric</th>
<th style="text-align: left;">.estimator</th>
<th style="text-align: right;">.estimate</th>
<th style="text-align: left;">.config</th>
</tr>
</thead>
<tbody>
<tr class="odd">
<td style="text-align: left;">Fold1</td>
<td style="text-align: left;">accuracy</td>
<td style="text-align: left;">binary</td>
<td style="text-align: right;">0.9511002</td>
<td style="text-align: left;">Preprocessor1_Model1</td>
</tr>
<tr class="even">
<td style="text-align: left;">Fold1</td>
<td style="text-align: left;">roc_auc</td>
<td style="text-align: left;">binary</td>
<td style="text-align: right;">0.8399100</td>
<td style="text-align: left;">Preprocessor1_Model1</td>
</tr>
<tr class="odd">
<td style="text-align: left;">Fold1</td>
<td style="text-align: left;">brier_class</td>
<td style="text-align: left;">binary</td>
<td style="text-align: right;">0.0421900</td>
<td style="text-align: left;">Preprocessor1_Model1</td>
</tr>
<tr class="even">
<td style="text-align: left;">Fold2</td>
<td style="text-align: left;">accuracy</td>
<td style="text-align: left;">binary</td>
<td style="text-align: right;">0.9474328</td>
<td style="text-align: left;">Preprocessor1_Model1</td>
</tr>
<tr class="odd">
<td style="text-align: left;">Fold2</td>
<td style="text-align: left;">roc_auc</td>
<td style="text-align: left;">binary</td>
<td style="text-align: right;">0.8530833</td>
<td style="text-align: left;">Preprocessor1_Model1</td>
</tr>
<tr class="even">
<td style="text-align: left;">Fold2</td>
<td style="text-align: left;">brier_class</td>
<td style="text-align: left;">binary</td>
<td style="text-align: right;">0.0447018</td>
<td style="text-align: left;">Preprocessor1_Model1</td>
</tr>
<tr class="odd">
<td style="text-align: left;">Fold3</td>
<td style="text-align: left;">accuracy</td>
<td style="text-align: left;">binary</td>
<td style="text-align: right;">0.9511002</td>
<td style="text-align: left;">Preprocessor1_Model1</td>
</tr>
<tr class="even">
<td style="text-align: left;">Fold3</td>
<td style="text-align: left;">roc_auc</td>
<td style="text-align: left;">binary</td>
<td style="text-align: right;">0.8170630</td>
<td style="text-align: left;">Preprocessor1_Model1</td>
</tr>
<tr class="odd">
<td style="text-align: left;">Fold3</td>
<td style="text-align: left;">brier_class</td>
<td style="text-align: left;">binary</td>
<td style="text-align: right;">0.0436958</td>
<td style="text-align: left;">Preprocessor1_Model1</td>
</tr>
<tr class="even">
<td style="text-align: left;">Fold4</td>
<td style="text-align: left;">accuracy</td>
<td style="text-align: left;">binary</td>
<td style="text-align: right;">0.9596083</td>
<td style="text-align: left;">Preprocessor1_Model1</td>
</tr>
<tr class="odd">
<td style="text-align: left;">Fold4</td>
<td style="text-align: left;">roc_auc</td>
<td style="text-align: left;">binary</td>
<td style="text-align: right;">0.7657313</td>
<td style="text-align: left;">Preprocessor1_Model1</td>
</tr>
<tr class="even">
<td style="text-align: left;">Fold4</td>
<td style="text-align: left;">brier_class</td>
<td style="text-align: left;">binary</td>
<td style="text-align: right;">0.0386978</td>
<td style="text-align: left;">Preprocessor1_Model1</td>
</tr>
</tbody>
</table>
</div>
</div>
<details open="" class="code-fold">
<summary>Code</summary>
<div class="sourceCode cell-code" id="cb8"><pre class="sourceCode numberSource r number-lines code-with-copy"><code class="sourceCode r"><span id="cb8-1"><a href="#cb8-1"></a><span class="co">#测试集评估</span></span>
<span id="cb8-2"><a href="#cb8-2"></a></span>
<span id="cb8-3"><a href="#cb8-3"></a>stroke_fit <span class="ot">&lt;-</span> </span>
<span id="cb8-4"><a href="#cb8-4"></a>  stroke_flow <span class="sc">%&gt;%</span> </span>
<span id="cb8-5"><a href="#cb8-5"></a>  <span class="fu">fit</span>(<span class="at">data =</span> train_stroke)</span>
<span id="cb8-6"><a href="#cb8-6"></a></span>
<span id="cb8-7"><a href="#cb8-7"></a>rf_stroke_aug <span class="ot">&lt;-</span> </span>
<span id="cb8-8"><a href="#cb8-8"></a>  <span class="fu">augment</span>(stroke_fit, test_stroke) <span class="sc">%&gt;%</span> </span>
<span id="cb8-9"><a href="#cb8-9"></a>  <span class="fu">select</span>(stroke,.pred_1,.pred_class)</span>
<span id="cb8-10"><a href="#cb8-10"></a></span>
<span id="cb8-11"><a href="#cb8-11"></a>rf_stroke_aug <span class="sc">%&gt;%</span>                   <span class="co"># test set predictions</span></span>
<span id="cb8-12"><a href="#cb8-12"></a>  <span class="fu">roc_auc</span>(<span class="at">truth =</span> stroke, .pred_1)</span></code><button title="Copy to Clipboard" class="code-copy-button"><i class="bi"></i></button></pre></div>
</details>
<div class="cell-output-display">
<div class="kable-table">
<table class="caption-top table table-sm table-striped small">
<thead>
<tr class="header">
<th style="text-align: left;">.metric</th>
<th style="text-align: left;">.estimator</th>
<th style="text-align: right;">.estimate</th>
</tr>
</thead>
<tbody>
<tr class="odd">
<td style="text-align: left;">roc_auc</td>
<td style="text-align: left;">binary</td>
<td style="text-align: right;">0.8092719</td>
</tr>
</tbody>
</table>
</div>
</div>
<details open="" class="code-fold">
<summary>Code</summary>
<div class="sourceCode cell-code" id="cb9"><pre class="sourceCode numberSource r number-lines code-with-copy"><code class="sourceCode r"><span id="cb9-1"><a href="#cb9-1"></a>rf_stroke_aug <span class="sc">%&gt;%</span> </span>
<span id="cb9-2"><a href="#cb9-2"></a>  <span class="fu">roc_curve</span>(<span class="at">truth =</span> stroke, .pred_1) <span class="sc">%&gt;%</span> <span class="co">#ROC曲线</span></span>
<span id="cb9-3"><a href="#cb9-3"></a>  <span class="fu">autoplot</span>()</span></code><button title="Copy to Clipboard" class="code-copy-button"><i class="bi"></i></button></pre></div>
</details>
<div class="cell-output-display">
<div>
<figure class="figure">
<p><img src="00.Preface_files/figure-html/unnamed-chunk-5-1.png" class="img-fluid figure-img" width="672"></p>
</figure>
</div>
</div>
</div>
<p>这次我们又用随机森林训练了一个模型，这个模型在训练时采用了5折交叉验证的方式，在训练过程中能够更客观的看待训练的效果，并减少偶然一次训练可能产生的过拟合等现象。但有一件事我们还没做，就是调参。在训练过程中，根据训练的效果，调整模型的参数，从而达到最佳效果。而本次我们并没有调参，都是用的默认参数，预测效果不一定最佳。我们将在后面的课时对机器学习的各个步骤进行详细讲解，实现模型性能的提升，达到最佳效果。</p>
</section>
<section id="模型的选择和快速构建" class="level3" data-number="5.4">
<h3 data-number="5.4" class="anchored" data-anchor-id="模型的选择和快速构建"><span class="header-section-number">5.4</span> 模型的选择和快速构建</h3>
<p>大家体会到了tidymodels的便捷，但究竟它支持多少种模型，又如何更加快速的进行构建呢？我们需要两个工具</p>
<p>1.<a href="https://www.tidymodels.org/find/parsnip/">Search parsnip models</a>,从这里我们可以查到所有支持的模型. 2.使用<code>usemodels</code>包来自动构建整个机器学习的全流程(但支持的模型有限).</p>
<div class="cell">
<details open="" class="code-fold">
<summary>Code</summary>
<div class="sourceCode cell-code" id="cb10"><pre class="sourceCode numberSource r number-lines code-with-copy"><code class="sourceCode r"><span id="cb10-1"><a href="#cb10-1"></a><span class="co">#使用glmnet建模</span></span>
<span id="cb10-2"><a href="#cb10-2"></a><span class="fu">use_glmnet</span>(stroke <span class="sc">~</span> ., strokedf)</span></code><button title="Copy to Clipboard" class="code-copy-button"><i class="bi"></i></button></pre></div>
</details>
<div class="cell-output cell-output-stdout">
<pre><code>glmnet_recipe &lt;- 
  recipe(formula = stroke ~ ., data = strokedf) %&gt;% 
  step_zv(all_predictors()) %&gt;% 
  step_normalize(all_numeric_predictors()) 

glmnet_spec &lt;- 
  logistic_reg(penalty = tune(), mixture = tune()) %&gt;% 
  set_mode("classification") %&gt;% 
  set_engine("glmnet") 

glmnet_workflow &lt;- 
  workflow() %&gt;% 
  add_recipe(glmnet_recipe) %&gt;% 
  add_model(glmnet_spec) 

glmnet_grid &lt;- tidyr::crossing(penalty = 10^seq(-6, -1, length.out = 20), mixture = c(0.05, 
    0.2, 0.4, 0.6, 0.8, 1)) 

glmnet_tune &lt;- 
  tune_grid(glmnet_workflow, resamples = stop("add your rsample object"), grid = glmnet_grid) </code></pre>
</div>
</div>
</section>
</section>
<section id="homework" class="level2" data-number="6">
<h2 data-number="6" class="anchored" data-anchor-id="homework"><span class="header-section-number">6</span> Homework</h2>
<p>有一个新的数据集<code>./datasets/stroke_prediction.csv</code>,也是中风(Diagnosis为Response)预测,数据集按9:1进行划分,请你用C5.0引擎,decision_tree(决策树)模型,10折交叉验证进行训练,并展示结果,最后在test set进行结果预测,并展示roc曲线.</p>
</section>
<section id="session-information" class="level2" data-number="7">
<h2 data-number="7" class="anchored" data-anchor-id="session-information"><span class="header-section-number">7</span> Session information</h2>
<div class="cell">
<details open="" class="code-fold">
<summary>Code</summary>
<div class="sourceCode cell-code" id="cb12"><pre class="sourceCode numberSource r number-lines code-with-copy"><code class="sourceCode r"><span id="cb12-1"><a href="#cb12-1"></a><span class="fu">sessionInfo</span>()</span></code><button title="Copy to Clipboard" class="code-copy-button"><i class="bi"></i></button></pre></div>
</details>
<div class="cell-output cell-output-stdout">
<pre><code>R version 4.4.0 (2024-04-24 ucrt)
Platform: x86_64-w64-mingw32/x64
Running under: Windows 11 x64 (build 22621)

Matrix products: default


locale:
[1] LC_COLLATE=Chinese (Simplified)_China.utf8 
[2] LC_CTYPE=Chinese (Simplified)_China.utf8   
[3] LC_MONETARY=Chinese (Simplified)_China.utf8
[4] LC_NUMERIC=C                               
[5] LC_TIME=Chinese (Simplified)_China.utf8    

time zone: Asia/Shanghai
tzcode source: internal

attached base packages:
[1] stats     graphics  grDevices utils     datasets  methods   base     

other attached packages:
 [1] ranger_0.16.0      magrittr_2.0.3     readr_2.1.5        usemodels_0.2.0   
 [5] yardstick_1.3.1    workflowsets_1.1.0 workflows_1.1.4    tune_1.2.1        
 [9] tidyr_1.3.1        tibble_3.2.1       rsample_1.2.1      recipes_1.1.0     
[13] purrr_1.0.2        parsnip_1.2.1      modeldata_1.4.0    infer_1.0.7       
[17] ggplot2_3.5.1      dplyr_1.1.4        dials_1.2.1        scales_1.3.0      
[21] broom_1.0.6        tidymodels_1.2.0  

loaded via a namespace (and not attached):
 [1] tidyselect_1.2.1    timeDate_4032.109   farver_2.1.2       
 [4] fastmap_1.2.0       digest_0.6.36       rpart_4.1.23       
 [7] timechange_0.3.0    lifecycle_1.0.4     survival_3.5-8     
[10] compiler_4.4.0      rlang_1.1.4         tools_4.4.0        
[13] utf8_1.2.4          yaml_2.3.9          data.table_1.15.4  
[16] knitr_1.48          labeling_0.4.3      bit_4.0.5          
[19] DiceDesign_1.10     withr_3.0.0         nnet_7.3-19        
[22] grid_4.4.0          fansi_1.0.6         colorspace_2.1-0   
[25] future_1.33.2       globals_0.16.3      iterators_1.0.14   
[28] MASS_7.3-60.2       cli_3.6.3           crayon_1.5.3       
[31] rmarkdown_2.27      generics_0.1.3      rstudioapi_0.16.0  
[34] future.apply_1.11.2 tzdb_0.4.0          splines_4.4.0      
[37] parallel_4.4.0      vctrs_0.6.5         hardhat_1.4.0      
[40] Matrix_1.7-0        jsonlite_1.8.8      hms_1.1.3          
[43] bit64_4.0.5         listenv_0.9.1       foreach_1.5.2      
[46] gower_1.0.1         glue_1.7.0          parallelly_1.37.1  
[49] codetools_0.2-20    lubridate_1.9.3     gtable_0.3.5       
[52] munsell_0.5.1       GPfit_1.0-8         pillar_1.9.0       
[55] furrr_0.3.1         htmltools_0.5.8.1   ipred_0.9-15       
[58] lava_1.8.0          R6_2.5.1            lhs_1.2.0          
[61] vroom_1.6.5         evaluate_0.24.0     lattice_0.22-6     
[64] backports_1.5.0     class_7.3-22        Rcpp_1.0.13        
[67] prodlim_2024.06.25  xfun_0.46           pkgconfig_2.0.3    </code></pre>
</div>
</div>
<!-- -->

<div class="hidden" aria-hidden="true">
<span class="glightbox-desc lightbox-desc-1">Figure&nbsp;3: workflow of packages</span>
<span class="glightbox-desc lightbox-desc-2">Figure&nbsp;4: 5折交叉验证</span>
</div>
</section>

</main>
<!-- /main column -->
<script id="quarto-html-after-body" type="application/javascript">
window.document.addEventListener("DOMContentLoaded", function (event) {
  const toggleBodyColorMode = (bsSheetEl) => {
    const mode = bsSheetEl.getAttribute("data-mode");
    const bodyEl = window.document.querySelector("body");
    if (mode === "dark") {
      bodyEl.classList.add("quarto-dark");
      bodyEl.classList.remove("quarto-light");
    } else {
      bodyEl.classList.add("quarto-light");
      bodyEl.classList.remove("quarto-dark");
    }
  }
  const toggleBodyColorPrimary = () => {
    const bsSheetEl = window.document.querySelector("link#quarto-bootstrap");
    if (bsSheetEl) {
      toggleBodyColorMode(bsSheetEl);
    }
  }
  toggleBodyColorPrimary();  
  const icon = "";
  const anchorJS = new window.AnchorJS();
  anchorJS.options = {
    placement: 'right',
    icon: icon
  };
  anchorJS.add('.anchored');
  const isCodeAnnotation = (el) => {
    for (const clz of el.classList) {
      if (clz.startsWith('code-annotation-')) {                     
        return true;
      }
    }
    return false;
  }
  const clipboard = new window.ClipboardJS('.code-copy-button', {
    text: function(trigger) {
      const codeEl = trigger.previousElementSibling.cloneNode(true);
      for (const childEl of codeEl.children) {
        if (isCodeAnnotation(childEl)) {
          childEl.remove();
        }
      }
      return codeEl.innerText;
    }
  });
  clipboard.on('success', function(e) {
    // button target
    const button = e.trigger;
    // don't keep focus
    button.blur();
    // flash "checked"
    button.classList.add('code-copy-button-checked');
    var currentTitle = button.getAttribute("title");
    button.setAttribute("title", "Copied!");
    let tooltip;
    if (window.bootstrap) {
      button.setAttribute("data-bs-toggle", "tooltip");
      button.setAttribute("data-bs-placement", "left");
      button.setAttribute("data-bs-title", "Copied!");
      tooltip = new bootstrap.Tooltip(button, 
        { trigger: "manual", 
          customClass: "code-copy-button-tooltip",
          offset: [0, -8]});
      tooltip.show();    
    }
    setTimeout(function() {
      if (tooltip) {
        tooltip.hide();
        button.removeAttribute("data-bs-title");
        button.removeAttribute("data-bs-toggle");
        button.removeAttribute("data-bs-placement");
      }
      button.setAttribute("title", currentTitle);
      button.classList.remove('code-copy-button-checked');
    }, 1000);
    // clear code selection
    e.clearSelection();
  });
  const viewSource = window.document.getElementById('quarto-view-source') ||
                     window.document.getElementById('quarto-code-tools-source');
  if (viewSource) {
    const sourceUrl = viewSource.getAttribute("data-quarto-source-url");
    viewSource.addEventListener("click", function(e) {
      if (sourceUrl) {
        // rstudio viewer pane
        if (/\bcapabilities=\b/.test(window.location)) {
          window.open(sourceUrl);
        } else {
          window.location.href = sourceUrl;
        }
      } else {
        const modal = new bootstrap.Modal(document.getElementById('quarto-embedded-source-code-modal'));
        modal.show();
      }
      return false;
    });
  }
  function toggleCodeHandler(show) {
    return function(e) {
      const detailsSrc = window.document.querySelectorAll(".cell > details > .sourceCode");
      for (let i=0; i<detailsSrc.length; i++) {
        const details = detailsSrc[i].parentElement;
        if (show) {
          details.open = true;
        } else {
          details.removeAttribute("open");
        }
      }
      const cellCodeDivs = window.document.querySelectorAll(".cell > .sourceCode");
      const fromCls = show ? "hidden" : "unhidden";
      const toCls = show ? "unhidden" : "hidden";
      for (let i=0; i<cellCodeDivs.length; i++) {
        const codeDiv = cellCodeDivs[i];
        if (codeDiv.classList.contains(fromCls)) {
          codeDiv.classList.remove(fromCls);
          codeDiv.classList.add(toCls);
        } 
      }
      return false;
    }
  }
  const hideAllCode = window.document.getElementById("quarto-hide-all-code");
  if (hideAllCode) {
    hideAllCode.addEventListener("click", toggleCodeHandler(false));
  }
  const showAllCode = window.document.getElementById("quarto-show-all-code");
  if (showAllCode) {
    showAllCode.addEventListener("click", toggleCodeHandler(true));
  }
    var localhostRegex = new RegExp(/^(?:http|https):\/\/localhost\:?[0-9]*\//);
    var mailtoRegex = new RegExp(/^mailto:/);
      var filterRegex = new RegExp('/' + window.location.host + '/');
    var isInternal = (href) => {
        return filterRegex.test(href) || localhostRegex.test(href) || mailtoRegex.test(href);
    }
    // Inspect non-navigation links and adorn them if external
 	var links = window.document.querySelectorAll('a[href]:not(.nav-link):not(.navbar-brand):not(.toc-action):not(.sidebar-link):not(.sidebar-item-toggle):not(.pagination-link):not(.no-external):not([aria-hidden]):not(.dropdown-item):not(.quarto-navigation-tool)');
    for (var i=0; i<links.length; i++) {
      const link = links[i];
      if (!isInternal(link.href)) {
        // undo the damage that might have been done by quarto-nav.js in the case of
        // links that we want to consider external
        if (link.dataset.originalHref !== undefined) {
          link.href = link.dataset.originalHref;
        }
      }
    }
  function tippyHover(el, contentFn, onTriggerFn, onUntriggerFn) {
    const config = {
      allowHTML: true,
      maxWidth: 500,
      delay: 100,
      arrow: false,
      appendTo: function(el) {
          return el.parentElement;
      },
      interactive: true,
      interactiveBorder: 10,
      theme: 'quarto',
      placement: 'bottom-start',
    };
    if (contentFn) {
      config.content = contentFn;
    }
    if (onTriggerFn) {
      config.onTrigger = onTriggerFn;
    }
    if (onUntriggerFn) {
      config.onUntrigger = onUntriggerFn;
    }
    window.tippy(el, config); 
  }
  const noterefs = window.document.querySelectorAll('a[role="doc-noteref"]');
  for (var i=0; i<noterefs.length; i++) {
    const ref = noterefs[i];
    tippyHover(ref, function() {
      // use id or data attribute instead here
      let href = ref.getAttribute('data-footnote-href') || ref.getAttribute('href');
      try { href = new URL(href).hash; } catch {}
      const id = href.replace(/^#\/?/, "");
      const note = window.document.getElementById(id);
      if (note) {
        return note.innerHTML;
      } else {
        return "";
      }
    });
  }
  const xrefs = window.document.querySelectorAll('a.quarto-xref');
  const processXRef = (id, note) => {
    // Strip column container classes
    const stripColumnClz = (el) => {
      el.classList.remove("page-full", "page-columns");
      if (el.children) {
        for (const child of el.children) {
          stripColumnClz(child);
        }
      }
    }
    stripColumnClz(note)
    if (id === null || id.startsWith('sec-')) {
      // Special case sections, only their first couple elements
      const container = document.createElement("div");
      if (note.children && note.children.length > 2) {
        container.appendChild(note.children[0].cloneNode(true));
        for (let i = 1; i < note.children.length; i++) {
          const child = note.children[i];
          if (child.tagName === "P" && child.innerText === "") {
            continue;
          } else {
            container.appendChild(child.cloneNode(true));
            break;
          }
        }
        if (window.Quarto?.typesetMath) {
          window.Quarto.typesetMath(container);
        }
        return container.innerHTML
      } else {
        if (window.Quarto?.typesetMath) {
          window.Quarto.typesetMath(note);
        }
        return note.innerHTML;
      }
    } else {
      // Remove any anchor links if they are present
      const anchorLink = note.querySelector('a.anchorjs-link');
      if (anchorLink) {
        anchorLink.remove();
      }
      if (window.Quarto?.typesetMath) {
        window.Quarto.typesetMath(note);
      }
      // TODO in 1.5, we should make sure this works without a callout special case
      if (note.classList.contains("callout")) {
        return note.outerHTML;
      } else {
        return note.innerHTML;
      }
    }
  }
  for (var i=0; i<xrefs.length; i++) {
    const xref = xrefs[i];
    tippyHover(xref, undefined, function(instance) {
      instance.disable();
      let url = xref.getAttribute('href');
      let hash = undefined; 
      if (url.startsWith('#')) {
        hash = url;
      } else {
        try { hash = new URL(url).hash; } catch {}
      }
      if (hash) {
        const id = hash.replace(/^#\/?/, "");
        const note = window.document.getElementById(id);
        if (note !== null) {
          try {
            const html = processXRef(id, note.cloneNode(true));
            instance.setContent(html);
          } finally {
            instance.enable();
            instance.show();
          }
        } else {
          // See if we can fetch this
          fetch(url.split('#')[0])
          .then(res => res.text())
          .then(html => {
            const parser = new DOMParser();
            const htmlDoc = parser.parseFromString(html, "text/html");
            const note = htmlDoc.getElementById(id);
            if (note !== null) {
              const html = processXRef(id, note);
              instance.setContent(html);
            } 
          }).finally(() => {
            instance.enable();
            instance.show();
          });
        }
      } else {
        // See if we can fetch a full url (with no hash to target)
        // This is a special case and we should probably do some content thinning / targeting
        fetch(url)
        .then(res => res.text())
        .then(html => {
          const parser = new DOMParser();
          const htmlDoc = parser.parseFromString(html, "text/html");
          const note = htmlDoc.querySelector('main.content');
          if (note !== null) {
            // This should only happen for chapter cross references
            // (since there is no id in the URL)
            // remove the first header
            if (note.children.length > 0 && note.children[0].tagName === "HEADER") {
              note.children[0].remove();
            }
            const html = processXRef(null, note);
            instance.setContent(html);
          } 
        }).finally(() => {
          instance.enable();
          instance.show();
        });
      }
    }, function(instance) {
    });
  }
      let selectedAnnoteEl;
      const selectorForAnnotation = ( cell, annotation) => {
        let cellAttr = 'data-code-cell="' + cell + '"';
        let lineAttr = 'data-code-annotation="' +  annotation + '"';
        const selector = 'span[' + cellAttr + '][' + lineAttr + ']';
        return selector;
      }
      const selectCodeLines = (annoteEl) => {
        const doc = window.document;
        const targetCell = annoteEl.getAttribute("data-target-cell");
        const targetAnnotation = annoteEl.getAttribute("data-target-annotation");
        const annoteSpan = window.document.querySelector(selectorForAnnotation(targetCell, targetAnnotation));
        const lines = annoteSpan.getAttribute("data-code-lines").split(",");
        const lineIds = lines.map((line) => {
          return targetCell + "-" + line;
        })
        let top = null;
        let height = null;
        let parent = null;
        if (lineIds.length > 0) {
            //compute the position of the single el (top and bottom and make a div)
            const el = window.document.getElementById(lineIds[0]);
            top = el.offsetTop;
            height = el.offsetHeight;
            parent = el.parentElement.parentElement;
          if (lineIds.length > 1) {
            const lastEl = window.document.getElementById(lineIds[lineIds.length - 1]);
            const bottom = lastEl.offsetTop + lastEl.offsetHeight;
            height = bottom - top;
          }
          if (top !== null && height !== null && parent !== null) {
            // cook up a div (if necessary) and position it 
            let div = window.document.getElementById("code-annotation-line-highlight");
            if (div === null) {
              div = window.document.createElement("div");
              div.setAttribute("id", "code-annotation-line-highlight");
              div.style.position = 'absolute';
              parent.appendChild(div);
            }
            div.style.top = top - 2 + "px";
            div.style.height = height + 4 + "px";
            div.style.left = 0;
            let gutterDiv = window.document.getElementById("code-annotation-line-highlight-gutter");
            if (gutterDiv === null) {
              gutterDiv = window.document.createElement("div");
              gutterDiv.setAttribute("id", "code-annotation-line-highlight-gutter");
              gutterDiv.style.position = 'absolute';
              const codeCell = window.document.getElementById(targetCell);
              const gutter = codeCell.querySelector('.code-annotation-gutter');
              gutter.appendChild(gutterDiv);
            }
            gutterDiv.style.top = top - 2 + "px";
            gutterDiv.style.height = height + 4 + "px";
          }
          selectedAnnoteEl = annoteEl;
        }
      };
      const unselectCodeLines = () => {
        const elementsIds = ["code-annotation-line-highlight", "code-annotation-line-highlight-gutter"];
        elementsIds.forEach((elId) => {
          const div = window.document.getElementById(elId);
          if (div) {
            div.remove();
          }
        });
        selectedAnnoteEl = undefined;
      };
        // Handle positioning of the toggle
    window.addEventListener(
      "resize",
      throttle(() => {
        elRect = undefined;
        if (selectedAnnoteEl) {
          selectCodeLines(selectedAnnoteEl);
        }
      }, 10)
    );
    function throttle(fn, ms) {
    let throttle = false;
    let timer;
      return (...args) => {
        if(!throttle) { // first call gets through
            fn.apply(this, args);
            throttle = true;
        } else { // all the others get throttled
            if(timer) clearTimeout(timer); // cancel #2
            timer = setTimeout(() => {
              fn.apply(this, args);
              timer = throttle = false;
            }, ms);
        }
      };
    }
      // Attach click handler to the DT
      const annoteDls = window.document.querySelectorAll('dt[data-target-cell]');
      for (const annoteDlNode of annoteDls) {
        annoteDlNode.addEventListener('click', (event) => {
          const clickedEl = event.target;
          if (clickedEl !== selectedAnnoteEl) {
            unselectCodeLines();
            const activeEl = window.document.querySelector('dt[data-target-cell].code-annotation-active');
            if (activeEl) {
              activeEl.classList.remove('code-annotation-active');
            }
            selectCodeLines(clickedEl);
            clickedEl.classList.add('code-annotation-active');
          } else {
            // Unselect the line
            unselectCodeLines();
            clickedEl.classList.remove('code-annotation-active');
          }
        });
      }
  const findCites = (el) => {
    const parentEl = el.parentElement;
    if (parentEl) {
      const cites = parentEl.dataset.cites;
      if (cites) {
        return {
          el,
          cites: cites.split(' ')
        };
      } else {
        return findCites(el.parentElement)
      }
    } else {
      return undefined;
    }
  };
  var bibliorefs = window.document.querySelectorAll('a[role="doc-biblioref"]');
  for (var i=0; i<bibliorefs.length; i++) {
    const ref = bibliorefs[i];
    const citeInfo = findCites(ref);
    if (citeInfo) {
      tippyHover(citeInfo.el, function() {
        var popup = window.document.createElement('div');
        citeInfo.cites.forEach(function(cite) {
          var citeDiv = window.document.createElement('div');
          citeDiv.classList.add('hanging-indent');
          citeDiv.classList.add('csl-entry');
          var biblioDiv = window.document.getElementById('ref-' + cite);
          if (biblioDiv) {
            citeDiv.innerHTML = biblioDiv.innerHTML;
          }
          popup.appendChild(citeDiv);
        });
        return popup.innerHTML;
      });
    }
  }
});
</script><div class="modal fade" id="quarto-embedded-source-code-modal" tabindex="-1" aria-labelledby="quarto-embedded-source-code-modal-label" aria-hidden="true"><div class="modal-dialog modal-dialog-scrollable"><div class="modal-content"><div class="modal-header"><h5 class="modal-title" id="quarto-embedded-source-code-modal-label">Source Code</h5><button class="btn-close" data-bs-dismiss="modal"></button></div><div class="modal-body"><div class="">
<div class="sourceCode" id="cb14" data-shortcodes="false"><pre class="sourceCode numberSource markdown number-lines code-with-copy"><code class="sourceCode markdown"><span id="cb14-1"><a href="#cb14-1"></a><span class="co">---</span></span>
<span id="cb14-2"><a href="#cb14-2"></a><span class="an">title:</span><span class="co"> "医学生入门机器学习-tidymodels基础与流程"</span></span>
<span id="cb14-3"><a href="#cb14-3"></a><span class="an">author:</span></span>
<span id="cb14-4"><a href="#cb14-4"></a><span class="co">  - name: 梁昊</span></span>
<span id="cb14-5"><a href="#cb14-5"></a><span class="co">    affiliations:</span></span>
<span id="cb14-6"><a href="#cb14-6"></a><span class="co">      - 医咖会</span></span>
<span id="cb14-7"><a href="#cb14-7"></a><span class="co">      - 湖南中医药大学</span></span>
<span id="cb14-8"><a href="#cb14-8"></a></span>
<span id="cb14-9"><a href="#cb14-9"></a><span class="an">format:</span></span>
<span id="cb14-10"><a href="#cb14-10"></a><span class="co">  html:</span></span>
<span id="cb14-11"><a href="#cb14-11"></a><span class="co">    toc: true</span></span>
<span id="cb14-12"><a href="#cb14-12"></a><span class="co">    number-sections: true</span></span>
<span id="cb14-13"><a href="#cb14-13"></a><span class="co">    toc-depth: 3</span></span>
<span id="cb14-14"><a href="#cb14-14"></a><span class="co">    code-fold: show</span></span>
<span id="cb14-15"><a href="#cb14-15"></a><span class="co">    code-tools: true</span></span>
<span id="cb14-16"><a href="#cb14-16"></a><span class="co">    code-line-numbers: true</span></span>
<span id="cb14-17"><a href="#cb14-17"></a><span class="co">    df-print: kable</span></span>
<span id="cb14-18"><a href="#cb14-18"></a><span class="co">---</span></span>
<span id="cb14-19"><a href="#cb14-19"></a></span>
<span id="cb14-20"><a href="#cb14-20"></a><span class="fu">## 写给医学伙伴的悄悄话</span></span>
<span id="cb14-21"><a href="#cb14-21"></a></span>
<span id="cb14-22"><a href="#cb14-22"></a>我是来自双非高校的一名普通老师，在探索医学和计算机学科的交叉过程中，走了很多弯路，这些路我不希望大家重走，而是直接迈入学习的**快车道**。</span>
<span id="cb14-23"><a href="#cb14-23"></a></span>
<span id="cb14-24"><a href="#cb14-24"></a>现今机器学习领域已经得到了极大发展，各种机器学习的工具和包层出不穷，自动化机器学习(auto machine learning，AutoML)的理念已经深入人心，无论什么领域，都应该专注**业务本身**，而非代码或算法，那是程序员和数学家的事，我们要做的就是如何用AutoML解决我们医学上的问题，而不是让编程和数学基础成为你解决科学问题的绊脚石。</span>
<span id="cb14-25"><a href="#cb14-25"></a></span>
<span id="cb14-26"><a href="#cb14-26"></a>机器学习领域Python和R已经是毫无争议的最佳编程语言。这其中tidymodels是R在AutoML领域的集大成者，学会了就能快速构建完整的机器学习。</span>
<span id="cb14-27"><a href="#cb14-27"></a></span>
<span id="cb14-28"><a href="#cb14-28"></a><span class="fu">## 医学数据</span></span>
<span id="cb14-29"><a href="#cb14-29"></a></span>
<span id="cb14-30"><a href="#cb14-30"></a>关于机器学习的很多基础概念，推荐大家到<span class="co">[</span><span class="ot">ShowMeAI知识社区-图解机器学习 | 机器学习基础知识</span><span class="co">](https://www.showmeai.tech/article-detail/185)</span>查看。许多基础的概念，我不会在这里解释，也是督促大家自学。</span>
<span id="cb14-31"><a href="#cb14-31"></a></span>
<span id="cb14-32"><a href="#cb14-32"></a>我们首先要认识到，不同的数据，处理和分析的方式不同，就像杀苍蝇用手枪，如果用错了工具，任务是无法完成的。</span>
<span id="cb14-33"><a href="#cb14-33"></a></span>
<span id="cb14-34"><a href="#cb14-34"></a>医学常见的数据有哪些？</span>
<span id="cb14-35"><a href="#cb14-35"></a></span>
<span id="cb14-36"><a href="#cb14-36"></a><span class="fu">### 文本数据</span></span>
<span id="cb14-37"><a href="#cb14-37"></a></span>
<span id="cb14-38"><a href="#cb14-38"></a>在这里，我把文本形式存储的数据全部叫文本数据。这些数据，有些是按照事先约定好的形式和格式采集和录入而形成的表格型数据（像excel），也有普通的一本书、一篇文章这样的纯粹文字数据。其中，表格型数据（dataframe）是我们使用最多，最需要掌握的数据类型。</span>
<span id="cb14-39"><a href="#cb14-39"></a></span>
<span id="cb14-40"><a href="#cb14-40"></a><span class="ss">1. </span>表格数据（dataframe）</span>
<span id="cb14-41"><a href="#cb14-41"></a></span>
<span id="cb14-42"><a href="#cb14-42"></a><span class="in">`dataframe`</span> 顾名思义，也叫方形数据（Rectangular Data）。Python（pandas包）和R都将这种数据称为dataframe，也是最常见的数据对象。</span>
<span id="cb14-43"><a href="#cb14-43"></a>在R中，还有<span class="in">`tibble`</span>和<span class="in">`data.table`</span>这类<span class="in">`dataframe`</span>的变种，本质上还是方形数据，只不过用来处理的包和风格不太相同。</span>
<span id="cb14-44"><a href="#cb14-44"></a></span>
<span id="cb14-45"><a href="#cb14-45"></a>:::{.callout-note}</span>
<span id="cb14-46"><a href="#cb14-46"></a></span>
<span id="cb14-47"><a href="#cb14-47"></a>tidymodels能够分析的主要是dataframe。</span>
<span id="cb14-48"><a href="#cb14-48"></a></span>
<span id="cb14-49"><a href="#cb14-49"></a>:::</span>
<span id="cb14-50"><a href="#cb14-50"></a></span>
<span id="cb14-51"><a href="#cb14-51"></a>下面的表格数据就是一个<span class="in">`dataframe`</span>例子</span>
<span id="cb14-52"><a href="#cb14-52"></a></span>
<span id="cb14-55"><a href="#cb14-55"></a><span class="in">```{r}</span></span>
<span id="cb14-56"><a href="#cb14-56"></a><span class="fu">head</span>(esoph,<span class="dv">8</span>)</span>
<span id="cb14-57"><a href="#cb14-57"></a></span>
<span id="cb14-58"><a href="#cb14-58"></a><span class="in">```</span></span>
<span id="cb14-59"><a href="#cb14-59"></a></span>
<span id="cb14-60"><a href="#cb14-60"></a></span>
<span id="cb14-61"><a href="#cb14-61"></a><span class="ss">2. </span>纯粹文本Plain text</span>
<span id="cb14-62"><a href="#cb14-62"></a></span>
<span id="cb14-63"><a href="#cb14-63"></a>纯文本，因为它纯了，就是普通不加任何清洗和修改的自然文字段落。</span>
<span id="cb14-64"><a href="#cb14-64"></a></span>
<span id="cb14-65"><a href="#cb14-65"></a><span class="fu">### 其他数据</span></span>
<span id="cb14-66"><a href="#cb14-66"></a></span>
<span id="cb14-67"><a href="#cb14-67"></a><span class="ss">- </span>时间序列Time series data</span>
<span id="cb14-68"><a href="#cb14-68"></a></span>
<span id="cb14-69"><a href="#cb14-69"></a>  大部分信号处理都是这类数据，比如心电图、股票、声波。</span>
<span id="cb14-70"><a href="#cb14-70"></a></span>
<span id="cb14-71"><a href="#cb14-71"></a><span class="ss">- </span>空间数据Spatial data</span>
<span id="cb14-72"><a href="#cb14-72"></a></span>
<span id="cb14-73"><a href="#cb14-73"></a>  地图、导航类似的数据。</span>
<span id="cb14-74"><a href="#cb14-74"></a></span>
<span id="cb14-75"><a href="#cb14-75"></a><span class="ss">- </span>图数据Graph (or network) data</span>
<span id="cb14-76"><a href="#cb14-76"></a></span>
<span id="cb14-77"><a href="#cb14-77"></a><span class="at">  &gt; In computer science and information technology, the term graph typically refers to a depiction of the connections among entities, and to the underlying data structure.在计算机科学和信息技术中，术语"图"通常指实体之间的连接和底层数据结构的描述。如图神经网络。平时我们看到的知识图谱就属于这一类。</span></span>
<span id="cb14-78"><a href="#cb14-78"></a></span>
<span id="cb14-79"><a href="#cb14-79"></a><span class="ss">- </span>图像和视频数据image data and video data</span>
<span id="cb14-80"><a href="#cb14-80"></a></span>
<span id="cb14-81"><a href="#cb14-81"></a><span class="fu">## 机器学习类型和业务逻辑</span></span>
<span id="cb14-82"><a href="#cb14-82"></a></span>
<span id="cb14-83"><a href="#cb14-83"></a>在确定我们需要的机器学习类型时，我们要根据我们的医学业务来明确以下问题。</span>
<span id="cb14-84"><a href="#cb14-84"></a></span>
<span id="cb14-85"><a href="#cb14-85"></a><span class="ss">1. </span>监督学习（预测的目标已做好标记，如死亡、患病）还是非监督学习（目标情况不清楚，比如哪两个中药搭配最常见）。</span>
<span id="cb14-86"><a href="#cb14-86"></a></span>
<span id="cb14-87"><a href="#cb14-87"></a><span class="ss">2. </span>明确哪个是要预测的目标Y。</span>
<span id="cb14-88"><a href="#cb14-88"></a></span>
<span id="cb14-89"><a href="#cb14-89"></a><span class="ss">3. </span>如果是监督学习，目标Y是分类问题，还是回归问题，如<span class="co">[</span><span class="ot">@fig-regressionclassification</span><span class="co">]</span>。</span>
<span id="cb14-90"><a href="#cb14-90"></a></span>
<span id="cb14-91"><a href="#cb14-91"></a><span class="al">![Regression vs Classification in Machine Learning](./images/regression-vs.-classification.png)</span>{#fig-regressionclassification}</span>
<span id="cb14-92"><a href="#cb14-92"></a></span>
<span id="cb14-93"><a href="#cb14-93"></a>::: callout-note</span>
<span id="cb14-94"><a href="#cb14-94"></a></span>
<span id="cb14-95"><a href="#cb14-95"></a><span class="ss">-   </span>In the regression problem, Y is numeric (e.g price, blood pressure).</span>
<span id="cb14-96"><a href="#cb14-96"></a><span class="ss">-   </span>In the classification problem, Y takes values in a finite, unordered set (survived/died, cancer class of tissue sample).</span>
<span id="cb14-97"><a href="#cb14-97"></a></span>
<span id="cb14-98"><a href="#cb14-98"></a>:::</span>
<span id="cb14-99"><a href="#cb14-99"></a></span>
<span id="cb14-100"><a href="#cb14-100"></a></span>
<span id="cb14-101"><a href="#cb14-101"></a>表格数据中列的列是<span class="in">`variable`</span>。作为医学研究，我们可以理解为研究对象的属性(attribute)，比如，病人的年龄、性别、收入等。<span class="in">`variable`</span>是根据你要做的研究业务需求而设立的，比如最常见的RCT研究，不同的治疗方法或者说治疗组+对照组一起构成了group这个<span class="in">`variable`</span>(列)。<span class="in">`variable`</span>在计算机领域也被称为字段。</span>
<span id="cb14-102"><a href="#cb14-102"></a></span>
<span id="cb14-103"><a href="#cb14-103"></a>variable根据业务需要，还可分为两类</span>
<span id="cb14-104"><a href="#cb14-104"></a></span>
<span id="cb14-105"><a href="#cb14-105"></a><span class="ss">- </span>自变量（X），也被称为input, predictor, (independent) variable, regressor, covariate, feature, explanatory variable</span>
<span id="cb14-106"><a href="#cb14-106"></a><span class="ss">- </span>因变量（Y），也被称为dependent variable, response, outcome, target, output, response variable</span>
<span id="cb14-107"><a href="#cb14-107"></a></span>
<span id="cb14-108"><a href="#cb14-108"></a>比如，下面这个数据，如果我们把是否早产<span class="in">`premature`</span>作为要预测的Y（response），其他变量就可以定为X（predictors）</span>
<span id="cb14-109"><a href="#cb14-109"></a></span>
<span id="cb14-112"><a href="#cb14-112"></a><span class="in">```{r}</span></span>
<span id="cb14-113"><a href="#cb14-113"></a><span class="co">#| label: tbl-birth</span></span>
<span id="cb14-114"><a href="#cb14-114"></a><span class="co">#| tbl-cap: "Birth table"</span></span>
<span id="cb14-115"><a href="#cb14-115"></a><span class="fu">load</span>(<span class="st">"./datasets/births.rda"</span>) </span>
<span id="cb14-116"><a href="#cb14-116"></a><span class="fu">head</span>(births,<span class="dv">10</span>) </span>
<span id="cb14-117"><a href="#cb14-117"></a><span class="in">```</span></span>
<span id="cb14-118"><a href="#cb14-118"></a></span>
<span id="cb14-119"><a href="#cb14-119"></a><span class="fu">## 机器学习的流程</span></span>
<span id="cb14-120"><a href="#cb14-120"></a></span>
<span id="cb14-121"><a href="#cb14-121"></a><span class="al">![workflow of machine learning](./images/workflow.png)</span>{#fig-workflow}</span>
<span id="cb14-122"><a href="#cb14-122"></a></span>
<span id="cb14-123"><a href="#cb14-123"></a>数据准备(包含预处理和特征工程) -&gt; 数据拆分-&gt; 选择模型 -&gt; 训练 -&gt; 评价 -&gt; 调参 -&gt; 再评价 -&gt; 应用(predict), <span class="co">[</span><span class="ot">@fig-workflow</span><span class="co">]</span></span>
<span id="cb14-124"><a href="#cb14-124"></a></span>
<span id="cb14-125"><a href="#cb14-125"></a><span class="at">&gt; "The tidymodels framework is a collection of packages for modeling and machine learning using tidyverse principles." - tidymodels.org</span></span>
<span id="cb14-126"><a href="#cb14-126"></a></span>
<span id="cb14-127"><a href="#cb14-127"></a>tidymodels 是用于数据科学建模的一系列的包。安装方法<span class="in">`install.packages("tidymodels")`</span></span>
<span id="cb14-128"><a href="#cb14-128"></a></span>
<span id="cb14-129"><a href="#cb14-129"></a><span class="in">`tidymodels`</span>包含了一系列的R包，这些包括。</span>
<span id="cb14-130"><a href="#cb14-130"></a></span>
<span id="cb14-131"><a href="#cb14-131"></a><span class="ss">1. </span>rsample 高效的数据拆分和重采样</span>
<span id="cb14-132"><a href="#cb14-132"></a><span class="ss">2. </span>parsnip 统一的模型接口，可用于尝试一系列模型，而不会陷入底层包的语法细节</span>
<span id="cb14-133"><a href="#cb14-133"></a><span class="ss">3. </span>recipes 是用于数据预处理和特征工程工具的整洁接口</span>
<span id="cb14-134"><a href="#cb14-134"></a><span class="ss">4. </span>workflow 将预处理、建模和后处理集合在一起,是最关键的包</span>
<span id="cb14-135"><a href="#cb14-135"></a><span class="ss">5. </span>tune 可帮助您优化模型的超参数</span>
<span id="cb14-136"><a href="#cb14-136"></a><span class="ss">6. </span>dials 创建和管理调整参数和参数网格与tune配合使用</span>
<span id="cb14-137"><a href="#cb14-137"></a><span class="ss">7. </span>yardstick 使用性能指标来衡量模型的效果</span>
<span id="cb14-138"><a href="#cb14-138"></a><span class="ss">8. </span>broom 将常见统计结果中的信息转换为用户友好、结构化的格式。</span>
<span id="cb14-139"><a href="#cb14-139"></a></span>
<span id="cb14-140"><a href="#cb14-140"></a>以上这些包在加载<span class="in">`tidymodels`</span>的时候会一起加载，还有很多其他有用的工具需要手动进行加载。</span>
<span id="cb14-141"><a href="#cb14-141"></a></span>
<span id="cb14-142"><a href="#cb14-142"></a>还有些其他的包，大家也可以看看<span class="co">[</span><span class="ot">R packages by tidymodels</span><span class="co">](https://tidymodels.r-universe.dev/builds)</span></span>
<span id="cb14-143"><a href="#cb14-143"></a></span>
<span id="cb14-144"><a href="#cb14-144"></a><span class="al">![workflow of packages](./images/flowpackage.png)</span>{.lightbox #fig-flowpackage}</span>
<span id="cb14-145"><a href="#cb14-145"></a></span>
<span id="cb14-146"><a href="#cb14-146"></a><span class="in">`tidymodels`</span>究竟怎么构建这个机器学习的过程,从这个<span class="co">[</span><span class="ot">@fig-flowpackage</span><span class="co">]</span>中,我们可以根据对应的包略见一二。</span>
<span id="cb14-147"><a href="#cb14-147"></a></span>
<span id="cb14-148"><a href="#cb14-148"></a>正所谓大道至简，我今天用一句话来阐释<span class="in">`tidymodels`</span>的监督机器学习实施步骤：</span>
<span id="cb14-149"><a href="#cb14-149"></a></span>
<span id="cb14-150"><a href="#cb14-150"></a>确定好你要预测的目标（response，regression or classification）， <span class="in">`rsample`</span>按照训练需要将数据进行分割，<span class="in">`recipes`</span>对数据进行预处理和特征工程，<span class="in">`parsnip`</span>选定一个模型和引擎，<span class="in">`yardstick`</span>确定模型的评价指标， <span class="in">`workflow`</span>将这些统筹起来，然后开始训练，评价反馈，用<span class="in">`tune`</span>调整模型并获得最佳模型，最终在test set 做最终模型评价。</span>
<span id="cb14-151"><a href="#cb14-151"></a></span>
<span id="cb14-152"><a href="#cb14-152"></a><span class="fu">## tidymodels实践</span></span>
<span id="cb14-153"><a href="#cb14-153"></a></span>
<span id="cb14-154"><a href="#cb14-154"></a>下面和我一起来分步完成一次机器学习实践吧。</span>
<span id="cb14-155"><a href="#cb14-155"></a></span>
<span id="cb14-156"><a href="#cb14-156"></a><span class="fu">### 载入package</span></span>
<span id="cb14-157"><a href="#cb14-157"></a></span>
<span id="cb14-160"><a href="#cb14-160"></a><span class="in">```{r}</span></span>
<span id="cb14-161"><a href="#cb14-161"></a><span class="co">#| warning: false</span></span>
<span id="cb14-162"><a href="#cb14-162"></a></span>
<span id="cb14-163"><a href="#cb14-163"></a><span class="fu">library</span>(tidymodels)</span>
<span id="cb14-164"><a href="#cb14-164"></a><span class="fu">library</span>(usemodels)</span>
<span id="cb14-165"><a href="#cb14-165"></a><span class="fu">library</span>(dplyr)</span>
<span id="cb14-166"><a href="#cb14-166"></a><span class="fu">library</span>(readr)</span>
<span id="cb14-167"><a href="#cb14-167"></a><span class="fu">library</span>(magrittr)</span>
<span id="cb14-168"><a href="#cb14-168"></a></span>
<span id="cb14-169"><a href="#cb14-169"></a><span class="in">```</span></span>
<span id="cb14-170"><a href="#cb14-170"></a></span>
<span id="cb14-171"><a href="#cb14-171"></a></span>
<span id="cb14-172"><a href="#cb14-172"></a><span class="fu">### tidymodels流程初体验</span></span>
<span id="cb14-173"><a href="#cb14-173"></a></span>
<span id="cb14-176"><a href="#cb14-176"></a><span class="in">```{r}</span></span>
<span id="cb14-177"><a href="#cb14-177"></a><span class="co">#| warning: false</span></span>
<span id="cb14-178"><a href="#cb14-178"></a><span class="co">#读取数据</span></span>
<span id="cb14-179"><a href="#cb14-179"></a>strokedf <span class="ot">&lt;-</span> <span class="fu">read_csv</span>(<span class="st">"./datasets/stroke_data.csv"</span>, <span class="at">col_types =</span> <span class="fu">cols</span>(<span class="at">stroke =</span> <span class="st">"f"</span>) ) </span>
<span id="cb14-180"><a href="#cb14-180"></a><span class="fu">set.seed</span>(<span class="dv">123</span>)</span>
<span id="cb14-181"><a href="#cb14-181"></a></span>
<span id="cb14-182"><a href="#cb14-182"></a><span class="co">#按照8：2对数据进行拆分Training，test</span></span>
<span id="cb14-183"><a href="#cb14-183"></a>data_split <span class="ot">&lt;-</span> <span class="fu">initial_split</span>(strokedf, </span>
<span id="cb14-184"><a href="#cb14-184"></a>                           <span class="at">prop =</span> <span class="fl">0.80</span>, </span>
<span id="cb14-185"><a href="#cb14-185"></a>                           <span class="at">strata =</span> stroke)</span>
<span id="cb14-186"><a href="#cb14-186"></a>train_stroke <span class="ot">&lt;-</span> <span class="fu">training</span>(data_split) </span>
<span id="cb14-187"><a href="#cb14-187"></a>test_stroke <span class="ot">&lt;-</span> <span class="fu">testing</span>(data_split)</span>
<span id="cb14-188"><a href="#cb14-188"></a></span>
<span id="cb14-189"><a href="#cb14-189"></a><span class="co">#数据预处理</span></span>
<span id="cb14-190"><a href="#cb14-190"></a>stroke_res <span class="ot">&lt;-</span> <span class="fu">recipe</span>(stroke <span class="sc">~</span> ., <span class="at">data =</span> train_stroke) <span class="sc">%&gt;%</span> </span>
<span id="cb14-191"><a href="#cb14-191"></a>  <span class="fu">update_role</span>(id, <span class="at">new_role =</span> <span class="st">"ID"</span>) <span class="sc">%&gt;%</span> </span>
<span id="cb14-192"><a href="#cb14-192"></a>  <span class="fu">step_impute_bag</span>(<span class="fu">all_predictors</span>()) <span class="sc">%&gt;%</span> </span>
<span id="cb14-193"><a href="#cb14-193"></a>  <span class="fu">step_normalize</span>(<span class="fu">all_numeric_predictors</span>()) <span class="sc">%&gt;%</span> </span>
<span id="cb14-194"><a href="#cb14-194"></a>  <span class="fu">step_zv</span>(<span class="fu">all_predictors</span>()) </span>
<span id="cb14-195"><a href="#cb14-195"></a></span>
<span id="cb14-196"><a href="#cb14-196"></a><span class="co">#设定模型</span></span>
<span id="cb14-197"><a href="#cb14-197"></a>lr_mod <span class="ot">&lt;-</span> </span>
<span id="cb14-198"><a href="#cb14-198"></a>  <span class="fu">logistic_reg</span>() <span class="sc">%&gt;%</span> <span class="co">#逻辑回归</span></span>
<span id="cb14-199"><a href="#cb14-199"></a>  <span class="fu">set_engine</span>(<span class="st">"glm"</span>)</span>
<span id="cb14-200"><a href="#cb14-200"></a></span>
<span id="cb14-201"><a href="#cb14-201"></a><span class="co">#workflow集成</span></span>
<span id="cb14-202"><a href="#cb14-202"></a>stroke_flow <span class="ot">&lt;-</span> </span>
<span id="cb14-203"><a href="#cb14-203"></a>  <span class="fu">workflow</span>() <span class="sc">%&gt;%</span> </span>
<span id="cb14-204"><a href="#cb14-204"></a>  <span class="fu">add_model</span>(lr_mod) <span class="sc">%&gt;%</span> </span>
<span id="cb14-205"><a href="#cb14-205"></a>  <span class="fu">add_recipe</span>(stroke_res)</span>
<span id="cb14-206"><a href="#cb14-206"></a>  </span>
<span id="cb14-207"><a href="#cb14-207"></a><span class="co">#训练模型（拟合）</span></span>
<span id="cb14-208"><a href="#cb14-208"></a>stroke_fit <span class="ot">&lt;-</span> </span>
<span id="cb14-209"><a href="#cb14-209"></a>  stroke_flow <span class="sc">%&gt;%</span> </span>
<span id="cb14-210"><a href="#cb14-210"></a>  <span class="fu">fit</span>(<span class="at">data =</span> train_stroke)</span>
<span id="cb14-211"><a href="#cb14-211"></a></span>
<span id="cb14-212"><a href="#cb14-212"></a><span class="co">#测试集评估</span></span>
<span id="cb14-213"><a href="#cb14-213"></a>stroke_aug <span class="ot">&lt;-</span> </span>
<span id="cb14-214"><a href="#cb14-214"></a>  <span class="fu">augment</span>(stroke_fit, test_stroke) <span class="sc">%&gt;%</span> </span>
<span id="cb14-215"><a href="#cb14-215"></a>  <span class="fu">select</span>(stroke,.pred_1,.pred_class)</span>
<span id="cb14-216"><a href="#cb14-216"></a></span>
<span id="cb14-217"><a href="#cb14-217"></a>stroke_aug <span class="sc">%&gt;%</span> </span>
<span id="cb14-218"><a href="#cb14-218"></a>  <span class="fu">roc_curve</span>(<span class="at">truth =</span> stroke, .pred_1) <span class="sc">%&gt;%</span> <span class="co">#ROC曲线</span></span>
<span id="cb14-219"><a href="#cb14-219"></a>  <span class="fu">autoplot</span>()</span>
<span id="cb14-220"><a href="#cb14-220"></a></span>
<span id="cb14-221"><a href="#cb14-221"></a>stroke_aug <span class="sc">%&gt;%</span> </span>
<span id="cb14-222"><a href="#cb14-222"></a>  <span class="fu">conf_mat</span>(stroke, .pred_class) <span class="sc">%&gt;%</span> <span class="co">#混淆矩阵</span></span>
<span id="cb14-223"><a href="#cb14-223"></a>  <span class="fu">autoplot</span>(<span class="at">type =</span> <span class="st">"heatmap"</span>)</span>
<span id="cb14-224"><a href="#cb14-224"></a></span>
<span id="cb14-225"><a href="#cb14-225"></a>stroke_aug <span class="sc">%&gt;%</span> </span>
<span id="cb14-226"><a href="#cb14-226"></a>  <span class="fu">roc_auc</span>(<span class="at">truth =</span> stroke, .pred_1) <span class="co">#AUC</span></span>
<span id="cb14-227"><a href="#cb14-227"></a></span>
<span id="cb14-228"><a href="#cb14-228"></a></span>
<span id="cb14-229"><a href="#cb14-229"></a><span class="in">```</span></span>
<span id="cb14-230"><a href="#cb14-230"></a></span>
<span id="cb14-231"><a href="#cb14-231"></a><span class="fu">### 交叉验证优化训练</span></span>
<span id="cb14-232"><a href="#cb14-232"></a></span>
<span id="cb14-233"><a href="#cb14-233"></a></span>
<span id="cb14-234"><a href="#cb14-234"></a>刚刚我们流程过了一遍，但有些同志可能会纳闷，好像训练的时候数据集没有划分啊！并没有Validation set这个。</span>
<span id="cb14-235"><a href="#cb14-235"></a>下面我们就以这种方式来训练，并且我们要提到一种叫交叉验证的训练方式(Cross-Validation)。什么是交叉验证，我们看<span class="co">[</span><span class="ot">@fig-folds</span><span class="co">]</span>，这就是一个典型的5折交叉验证，将Training set划分成5份，然后每1份都做一次Validation set，其余作为Training set，反复训练5次，取平均值。</span>
<span id="cb14-236"><a href="#cb14-236"></a></span>
<span id="cb14-237"><a href="#cb14-237"></a><span class="al">![5折交叉验证](./images/folds_cv.jpg)</span>{.lightbox #fig-folds}</span>
<span id="cb14-238"><a href="#cb14-238"></a></span>
<span id="cb14-239"><a href="#cb14-239"></a>k 折交叉验证对 k 个不同分组训练的结果进行平均来减少方差，因此模型的性能对数据的划分就不那么敏感，对数据的使用也会更充分，模型评估结果更加稳定。下面我们来以随机森林机器模型，采用5折交叉验证来实现一个新的训练。</span>
<span id="cb14-240"><a href="#cb14-240"></a></span>
<span id="cb14-243"><a href="#cb14-243"></a><span class="in">```{r}</span></span>
<span id="cb14-244"><a href="#cb14-244"></a><span class="co">#| warning: false</span></span>
<span id="cb14-245"><a href="#cb14-245"></a></span>
<span id="cb14-246"><a href="#cb14-246"></a><span class="co">#读取数据</span></span>
<span id="cb14-247"><a href="#cb14-247"></a>strokedf <span class="ot">&lt;-</span> <span class="fu">read_csv</span>(<span class="st">"./datasets/stroke_data.csv"</span>, <span class="at">col_types =</span> <span class="fu">cols</span>(<span class="at">stroke =</span> <span class="st">"f"</span>) ) </span>
<span id="cb14-248"><a href="#cb14-248"></a><span class="fu">set.seed</span>(<span class="dv">123</span>)</span>
<span id="cb14-249"><a href="#cb14-249"></a></span>
<span id="cb14-250"><a href="#cb14-250"></a><span class="co">#按照8：2对数据进行拆分Training，test</span></span>
<span id="cb14-251"><a href="#cb14-251"></a>data_split <span class="ot">&lt;-</span> <span class="fu">initial_split</span>(strokedf, </span>
<span id="cb14-252"><a href="#cb14-252"></a>                           <span class="at">prop =</span> <span class="fl">0.80</span>, </span>
<span id="cb14-253"><a href="#cb14-253"></a>                           <span class="at">strata =</span> stroke)</span>
<span id="cb14-254"><a href="#cb14-254"></a>train_stroke <span class="ot">&lt;-</span> <span class="fu">training</span>(data_split) </span>
<span id="cb14-255"><a href="#cb14-255"></a>test_stroke <span class="ot">&lt;-</span> <span class="fu">testing</span>(data_split)</span>
<span id="cb14-256"><a href="#cb14-256"></a></span>
<span id="cb14-257"><a href="#cb14-257"></a><span class="co">#数据预处理</span></span>
<span id="cb14-258"><a href="#cb14-258"></a>stroke_res <span class="ot">&lt;-</span> <span class="fu">recipe</span>(stroke <span class="sc">~</span> ., <span class="at">data =</span> train_stroke) <span class="sc">%&gt;%</span> </span>
<span id="cb14-259"><a href="#cb14-259"></a>  <span class="fu">update_role</span>(id, <span class="at">new_role =</span> <span class="st">"ID"</span>) <span class="sc">%&gt;%</span> </span>
<span id="cb14-260"><a href="#cb14-260"></a>  <span class="fu">step_impute_bag</span>(<span class="fu">all_predictors</span>()) <span class="sc">%&gt;%</span> </span>
<span id="cb14-261"><a href="#cb14-261"></a>  <span class="fu">step_normalize</span>(<span class="fu">all_numeric_predictors</span>()) <span class="sc">%&gt;%</span> </span>
<span id="cb14-262"><a href="#cb14-262"></a>  <span class="fu">step_zv</span>(<span class="fu">all_predictors</span>()) </span>
<span id="cb14-263"><a href="#cb14-263"></a></span>
<span id="cb14-264"><a href="#cb14-264"></a><span class="co">#设定模型</span></span>
<span id="cb14-265"><a href="#cb14-265"></a>rf_mod <span class="ot">&lt;-</span> </span>
<span id="cb14-266"><a href="#cb14-266"></a>  <span class="fu">rand_forest</span>(<span class="at">trees =</span> <span class="dv">1000</span>) <span class="sc">%&gt;%</span> <span class="co">#随机森林模型</span></span>
<span id="cb14-267"><a href="#cb14-267"></a>  <span class="fu">set_engine</span>(<span class="st">"ranger"</span>) <span class="sc">%&gt;%</span> </span>
<span id="cb14-268"><a href="#cb14-268"></a>  <span class="fu">set_mode</span>(<span class="st">"classification"</span>)</span>
<span id="cb14-269"><a href="#cb14-269"></a></span>
<span id="cb14-270"><a href="#cb14-270"></a><span class="co">#workflow集成</span></span>
<span id="cb14-271"><a href="#cb14-271"></a>stroke_flow <span class="ot">&lt;-</span> </span>
<span id="cb14-272"><a href="#cb14-272"></a>  <span class="fu">workflow</span>() <span class="sc">%&gt;%</span> </span>
<span id="cb14-273"><a href="#cb14-273"></a>  <span class="fu">add_recipe</span>(stroke_res)<span class="sc">%&gt;%</span> </span>
<span id="cb14-274"><a href="#cb14-274"></a>  <span class="fu">add_model</span>(rf_mod)</span>
<span id="cb14-275"><a href="#cb14-275"></a>  </span>
<span id="cb14-276"><a href="#cb14-276"></a>  </span>
<span id="cb14-277"><a href="#cb14-277"></a><span class="co"># Cross validation</span></span>
<span id="cb14-278"><a href="#cb14-278"></a><span class="fu">set.seed</span>(<span class="dv">123</span>)</span>
<span id="cb14-279"><a href="#cb14-279"></a>cv_folds <span class="ot">&lt;-</span> </span>
<span id="cb14-280"><a href="#cb14-280"></a>  <span class="fu">vfold_cv</span>(train_stroke, <span class="at">v =</span> <span class="dv">5</span>)</span>
<span id="cb14-281"><a href="#cb14-281"></a>  </span>
<span id="cb14-282"><a href="#cb14-282"></a><span class="co">#训练模型（拟合）</span></span>
<span id="cb14-283"><a href="#cb14-283"></a>rf_res <span class="ot">&lt;-</span> stroke_flow <span class="sc">%&gt;%</span></span>
<span id="cb14-284"><a href="#cb14-284"></a>  <span class="fu">fit_resamples</span>(cv_folds)</span>
<span id="cb14-285"><a href="#cb14-285"></a></span>
<span id="cb14-286"><a href="#cb14-286"></a><span class="fu">collect_metrics</span>(rf_res, <span class="at">summarize =</span> <span class="cn">FALSE</span>)</span>
<span id="cb14-287"><a href="#cb14-287"></a></span>
<span id="cb14-288"><a href="#cb14-288"></a><span class="co">#测试集评估</span></span>
<span id="cb14-289"><a href="#cb14-289"></a></span>
<span id="cb14-290"><a href="#cb14-290"></a>stroke_fit <span class="ot">&lt;-</span> </span>
<span id="cb14-291"><a href="#cb14-291"></a>  stroke_flow <span class="sc">%&gt;%</span> </span>
<span id="cb14-292"><a href="#cb14-292"></a>  <span class="fu">fit</span>(<span class="at">data =</span> train_stroke)</span>
<span id="cb14-293"><a href="#cb14-293"></a></span>
<span id="cb14-294"><a href="#cb14-294"></a>rf_stroke_aug <span class="ot">&lt;-</span> </span>
<span id="cb14-295"><a href="#cb14-295"></a>  <span class="fu">augment</span>(stroke_fit, test_stroke) <span class="sc">%&gt;%</span> </span>
<span id="cb14-296"><a href="#cb14-296"></a>  <span class="fu">select</span>(stroke,.pred_1,.pred_class)</span>
<span id="cb14-297"><a href="#cb14-297"></a></span>
<span id="cb14-298"><a href="#cb14-298"></a>rf_stroke_aug <span class="sc">%&gt;%</span>                   <span class="co"># test set predictions</span></span>
<span id="cb14-299"><a href="#cb14-299"></a>  <span class="fu">roc_auc</span>(<span class="at">truth =</span> stroke, .pred_1)</span>
<span id="cb14-300"><a href="#cb14-300"></a></span>
<span id="cb14-301"><a href="#cb14-301"></a>rf_stroke_aug <span class="sc">%&gt;%</span> </span>
<span id="cb14-302"><a href="#cb14-302"></a>  <span class="fu">roc_curve</span>(<span class="at">truth =</span> stroke, .pred_1) <span class="sc">%&gt;%</span> <span class="co">#ROC曲线</span></span>
<span id="cb14-303"><a href="#cb14-303"></a>  <span class="fu">autoplot</span>()</span>
<span id="cb14-304"><a href="#cb14-304"></a></span>
<span id="cb14-305"><a href="#cb14-305"></a><span class="in">```</span></span>
<span id="cb14-306"><a href="#cb14-306"></a></span>
<span id="cb14-307"><a href="#cb14-307"></a>这次我们又用随机森林训练了一个模型，这个模型在训练时采用了5折交叉验证的方式，在训练过程中能够更客观的看待训练的效果，并减少偶然一次训练可能产生的过拟合等现象。但有一件事我们还没做，就是调参。在训练过程中，根据训练的效果，调整模型的参数，从而达到最佳效果。而本次我们并没有调参，都是用的默认参数，预测效果不一定最佳。我们将在后面的课时对机器学习的各个步骤进行详细讲解，实现模型性能的提升，达到最佳效果。</span>
<span id="cb14-308"><a href="#cb14-308"></a></span>
<span id="cb14-309"><a href="#cb14-309"></a><span class="fu">### 模型的选择和快速构建</span></span>
<span id="cb14-310"><a href="#cb14-310"></a></span>
<span id="cb14-311"><a href="#cb14-311"></a>大家体会到了tidymodels的便捷，但究竟它支持多少种模型，又如何更加快速的进行构建呢？我们需要两个工具</span>
<span id="cb14-312"><a href="#cb14-312"></a></span>
<span id="cb14-313"><a href="#cb14-313"></a>1.<span class="co">[</span><span class="ot">Search parsnip models</span><span class="co">](https://www.tidymodels.org/find/parsnip/)</span>,从这里我们可以查到所有支持的模型.</span>
<span id="cb14-314"><a href="#cb14-314"></a>2.使用<span class="in">`usemodels`</span>包来自动构建整个机器学习的全流程(但支持的模型有限).</span>
<span id="cb14-315"><a href="#cb14-315"></a></span>
<span id="cb14-318"><a href="#cb14-318"></a><span class="in">```{r}</span></span>
<span id="cb14-319"><a href="#cb14-319"></a><span class="co">#| warning: false</span></span>
<span id="cb14-320"><a href="#cb14-320"></a></span>
<span id="cb14-321"><a href="#cb14-321"></a><span class="co">#使用glmnet建模</span></span>
<span id="cb14-322"><a href="#cb14-322"></a><span class="fu">use_glmnet</span>(stroke <span class="sc">~</span> ., strokedf)</span>
<span id="cb14-323"><a href="#cb14-323"></a><span class="in">```</span></span>
<span id="cb14-324"><a href="#cb14-324"></a></span>
<span id="cb14-325"><a href="#cb14-325"></a><span class="fu">## Homework</span></span>
<span id="cb14-326"><a href="#cb14-326"></a></span>
<span id="cb14-327"><a href="#cb14-327"></a>有一个新的数据集<span class="in">`./datasets/stroke_prediction.csv`</span>,也是中风(Diagnosis为Response)预测,数据集按9:1进行划分,请你用C5.0引擎,decision_tree(决策树)模型,10折交叉验证进行训练,并展示结果,最后在test set进行结果预测,并展示roc曲线.</span>
<span id="cb14-328"><a href="#cb14-328"></a></span>
<span id="cb14-329"><a href="#cb14-329"></a><span class="fu">## Session information</span></span>
<span id="cb14-332"><a href="#cb14-332"></a><span class="in">```{r}</span></span>
<span id="cb14-333"><a href="#cb14-333"></a><span class="fu">sessionInfo</span>()</span>
<span id="cb14-334"><a href="#cb14-334"></a><span class="in">```</span></span>
</code><button title="Copy to Clipboard" class="code-copy-button"><i class="bi"></i></button></pre></div>
</div></div></div></div></div>
</div> <!-- /content -->
<script>var lightboxQuarto = GLightbox({"selector":".lightbox","descPosition":"bottom","closeEffect":"zoom","loop":false,"openEffect":"zoom"});
window.onload = () => {
  lightboxQuarto.on('slide_before_load', (data) => {
    const { slideIndex, slideNode, slideConfig, player, trigger } = data;
    const href = trigger.getAttribute('href');
    if (href !== null) {
      const imgEl = window.document.querySelector(`a[href="${href}"] img`);
      if (imgEl !== null) {
        const srcAttr = imgEl.getAttribute("src");
        if (srcAttr && srcAttr.startsWith("data:")) {
          slideConfig.href = srcAttr;
        }
      }
    } 
  });

  lightboxQuarto.on('slide_after_load', (data) => {
    const { slideIndex, slideNode, slideConfig, player, trigger } = data;
    if (window.Quarto?.typesetMath) {
      window.Quarto.typesetMath(slideNode);
    }
  });

};
          </script>




</body></html>